Merge pull request #1 from magefree/master

Updating master by merging their master
This commit is contained in:
chrvanorle 2018-03-13 12:48:46 +01:00 committed by GitHub
commit 0da4e10c49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
137 changed files with 3299 additions and 699 deletions

2
.gitignore vendored
View file

@ -4,6 +4,7 @@ syntax: glob
Mage.Client/*.dck
Mage.Client/db
Mage.Client/gamelogs
Mage.Client/gamelogsJson
Mage.Client/*.log
Mage.Client/plugins/images
Mage.Client/plugins/plugin.data
@ -135,3 +136,4 @@ client_secrets.json
dependency-reduced-pom.xml
mage-bundle
/Mage.Client/game-*.json

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<groupId>org.mage</groupId>
@ -15,6 +15,7 @@
<name>Mage Client</name>
<dependencies>
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage</artifactId>
@ -68,6 +69,11 @@
<artifactId>jetlang</artifactId>
<version>0.2.9</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.286</version>
</dependency>
<dependency>
<groupId>com.jgoodies</groupId>
<artifactId>forms</artifactId>

View file

@ -1,7 +1,9 @@
package mage.client;
import java.util.*;
import mage.cards.decks.DeckCardLists;
import mage.client.chat.LocalCommands;
import mage.client.dialog.PreferencesDialog;
import mage.constants.ManaType;
import mage.constants.PlayerAction;
import mage.game.match.MatchOptions;
@ -14,8 +16,6 @@ import mage.remote.Session;
import mage.remote.SessionImpl;
import mage.view.*;
import java.util.*;
/**
* Created by IGOUDT on 15-9-2016.
*/
@ -26,8 +26,9 @@ public final class SessionHandler {
public static void startSession(MageFrame mageFrame) {
session = new SessionImpl(mageFrame);
session.setJsonLogActive("true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_LOG_AUTO_SAVE, "true")));
}
public static void ping() {
session.ping();
}
@ -322,7 +323,7 @@ public final class SessionHandler {
}
public static void updateDeck(UUID tableId, DeckCardLists deckCardLists) {
session.updateDeck(tableId, deckCardLists);
session.updateDeck(tableId, deckCardLists);
}
public static boolean emailAuthToken(Connection connection) {
@ -330,10 +331,10 @@ public final class SessionHandler {
}
public static boolean resetPassword(Connection connection) {
return session.resetPassword(connection);
return session.resetPassword(connection);
}
public static boolean register(Connection connection) {
return session.register(connection);
return session.register(connection);
}
}

View file

@ -853,7 +853,7 @@
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Unique"/>
<Property name="toolTipText" type="java.lang.String" value="Singleton rules."/>
<Property name="toolTipText" type="java.lang.String" value="Show only the first found card of every card name."/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="4"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
@ -871,7 +871,6 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="chkUniqueActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="jButtonSearch">
<Properties>
<Property name="text" type="java.lang.String" value="Search"/>

View file

@ -51,6 +51,10 @@ import mage.client.MageFrame;
import mage.client.cards.*;
import mage.client.constants.Constants.SortBy;
import mage.client.deckeditor.table.TableModel;
import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_NAMES;
import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_RULES;
import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_TYPES;
import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_UNIQUE;
import mage.client.util.GUISizeHelper;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
@ -144,9 +148,11 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
mainTable.setOpaque(false);
cbSortBy.setEnabled(false);
chkPiles.setEnabled(false);
// chkNames.setEnabled(true);
// chkTypes.setEnabled(true);
// chkRules.setEnabled(true);
chkNames.setSelected("true".equals(MageFrame.getPreferences().get(KEY_DECK_EDITOR_SEARCH_NAMES, "true")));
chkTypes.setSelected("true".equals(MageFrame.getPreferences().get(KEY_DECK_EDITOR_SEARCH_TYPES, "true")));
chkRules.setSelected("true".equals(MageFrame.getPreferences().get(KEY_DECK_EDITOR_SEARCH_RULES, "true")));
chkUnique.setSelected("true".equals(MageFrame.getPreferences().get(KEY_DECK_EDITOR_SEARCH_UNIQUE, "true")));
mainTable.addMouseListener(new MouseAdapter() {
@Override
@ -172,6 +178,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
public void cleanUp() {
this.cardGrid.clear();
this.mainModel.clear();
MageFrame.getPreferences().put(KEY_DECK_EDITOR_SEARCH_NAMES, Boolean.toString(chkNames.isSelected()));
MageFrame.getPreferences().put(KEY_DECK_EDITOR_SEARCH_RULES, Boolean.toString(chkRules.isSelected()));
MageFrame.getPreferences().put(KEY_DECK_EDITOR_SEARCH_TYPES, Boolean.toString(chkTypes.isSelected()));
MageFrame.getPreferences().put(KEY_DECK_EDITOR_SEARCH_UNIQUE, Boolean.toString(chkUnique.isSelected()));
}
public void changeGUISize() {
@ -413,12 +423,12 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
try {
java.util.List<Card> filteredCards = new ArrayList<>();
setCursor(new Cursor(Cursor.WAIT_CURSOR));
boolean chkPD = chkPennyDreadful.isSelected();
if (chkPD) {
generatePennyDreadfulHash();
}
if (limited) {
for (Card card : cards) {
if (filter.match(card, null)) {
@ -1063,10 +1073,10 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
chkRulesActionPerformed(evt);
}
});
chkUnique.setSelected(true);
chkUnique.setText("Unique");
chkUnique.setToolTipText("Singleton results only.");
chkUnique.setToolTipText("Show only the first found card of every card name.");
chkUnique.setFocusable(false);
chkUnique.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
chkUnique.setMaximumSize(new java.awt.Dimension(69, 16));
@ -1079,7 +1089,6 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
}
});
jButtonSearch.setText("Search");
jButtonSearch.setToolTipText("Performs the search.");
jButtonSearch.addActionListener(new java.awt.event.ActionListener() {
@ -1126,7 +1135,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
.addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGap(5, 5, 5)
.addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(5, 5, 5)
.addComponent(cardCountLabel)
@ -1357,9 +1366,9 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// TODO add your handling code here:
}//GEN-LAST:event_chkTypesActionPerformed
private void chkRulesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed
private void chkRulesActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}//GEN-LAST:event_chkRulesActionPerformed
}
private void chkUniqueActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_chkRulesActionPerformed
// TODO add your handling code here:
@ -1442,8 +1451,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JCheckBox chkPennyDreadful;
private javax.swing.JCheckBox chkPiles;
private javax.swing.JCheckBox chkRules;
private javax.swing.JCheckBox chkUnique;
private javax.swing.JCheckBox chkTypes;
private javax.swing.JCheckBox chkUnique;
private javax.swing.JButton jButtonAddToMain;
private javax.swing.JButton jButtonAddToSideboard;
private javax.swing.JButton jButtonClean;

View file

@ -30,7 +30,7 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblForest" alignment="1" min="-2" max="-2" attributes="0"/>
@ -40,31 +40,30 @@
<Component id="lblSwamp" alignment="1" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="btnAutoAdd" pref="122" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="btnAutoAdd" alignment="0" pref="85" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnMountain" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnIsland" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnForest" alignment="0" max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnSwamp" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnPlains" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnAdd" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnMountain" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnIsland" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnForest" alignment="0" max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnSwamp" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnPlains" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="panelSet" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -74,7 +73,7 @@
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="lblLandSet" min="-2" max="-2" attributes="0"/>
<Component id="panelSet" min="-2" max="-2" attributes="0"/>
<Component id="panelSet" min="-2" pref="23" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
@ -102,12 +101,13 @@
<Component id="spnSwamp" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnAutoAdd" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnAdd" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnAutoAdd" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -238,5 +238,11 @@
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="ckbFullArtLands">
<Properties>
<Property name="text" type="java.lang.String" value="Only use full art lands"/>
<Property name="toolTipText" type="java.lang.String" value="For example, lands from ZEN/UST/HOU"/>
</Properties>
</Component>
</SubComponents>
</Form>

View file

@ -36,6 +36,7 @@ import javax.swing.DefaultComboBoxModel;
import javax.swing.JLayeredPane;
import mage.Mana;
import mage.cards.Card;
import mage.cards.FrameStyle;
import mage.cards.decks.Deck;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
@ -134,7 +135,7 @@ public class AddLandDialog extends MageDialog {
this.setVisible(true);
}
private void addLands(String landName, int number) {
private void addLands(String landName, int number, boolean useFullArt) {
String landSetName = (String) cbLandSet.getSelectedItem();
CardCriteria criteria = new CardCriteria();
@ -157,9 +158,28 @@ public class AddLandDialog extends MageDialog {
cards = CardRepository.instance.findCards(criteria);
}
for (int i = 0; i < number; i++) {
int foundLands = 0;
int foundNoneAfter = 0;
for (int i = 0; foundLands != number && foundNoneAfter < 1000; i++) {
Card land = cards.get(RandomUtil.nextInt(cards.size())).getMockCard();
deck.getCards().add(land);
boolean useLand = !useFullArt;
if (useFullArt && (land.getFrameStyle() == FrameStyle.BFZ_FULL_ART_BASIC
|| land.getFrameStyle() == FrameStyle.UGL_FULL_ART_BASIC
|| land.getFrameStyle() == FrameStyle.UNH_FULL_ART_BASIC
|| land.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC)) {
useLand = true;
}
if (useLand) {
deck.getCards().add(land);
foundLands++;
foundNoneAfter = 0;
} else {
foundNoneAfter++;
}
}
if (foundNoneAfter >= 1000 && useFullArt) {
MageFrame.getInstance().showMessage("Unable to add enough " + landName + "s. You encountered an error in adding chosen lands. Unable to find enough full art lands in the set " + landSetName + ".");
}
}
@ -190,6 +210,7 @@ public class AddLandDialog extends MageDialog {
panelSet = new javax.swing.JPanel();
cbLandSet = new javax.swing.JComboBox();
btnSetFastSearch = new javax.swing.JButton();
ckbFullArtLands = new javax.swing.JCheckBox();
jButton2.setText("jButton2");
@ -255,12 +276,15 @@ public class AddLandDialog extends MageDialog {
});
panelSet.add(btnSetFastSearch);
ckbFullArtLands.setText("Only use full art lands");
ckbFullArtLands.setToolTipText("For example, lands from ZEN/UST/HOU");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblMountain)
.addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING)
@ -269,25 +293,24 @@ public class AddLandDialog extends MageDialog {
.addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(ckbFullArtLands)
.addGroup(layout.createSequentialGroup()
.addComponent(btnAutoAdd, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(btnAutoAdd, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnAdd)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING)))
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
.addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -295,7 +318,7 @@ public class AddLandDialog extends MageDialog {
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblLandSet)
.addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblForest)
@ -317,11 +340,12 @@ public class AddLandDialog extends MageDialog {
.addComponent(lblSwamp)
.addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(ckbFullArtLands)
.addGap(2, 2, 2)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnAutoAdd)
.addComponent(btnAdd)
.addComponent(btnCancel)
.addComponent(btnAutoAdd))
.addContainerGap())
.addComponent(btnCancel)))
);
pack();
@ -337,12 +361,13 @@ public class AddLandDialog extends MageDialog {
int nMountain = ((Number) spnMountain.getValue()).intValue();
int nPlains = ((Number) spnPlains.getValue()).intValue();
int nSwamp = ((Number) spnSwamp.getValue()).intValue();
boolean useFullArt = ckbFullArtLands.isSelected();
addLands("Forest", nForest);
addLands("Island", nIsland);
addLands("Mountain", nMountain);
addLands("Plains", nPlains);
addLands("Swamp", nSwamp);
addLands("Forest", nForest, useFullArt);
addLands("Island", nIsland, useFullArt);
addLands("Mountain", nMountain, useFullArt);
addLands("Plains", nPlains, useFullArt);
addLands("Swamp", nSwamp, useFullArt);
this.removeDialog();
}//GEN-LAST:event_btnAddActionPerformed
@ -400,6 +425,7 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JButton btnCancel;
private javax.swing.JButton btnSetFastSearch;
private javax.swing.JComboBox cbLandSet;
private javax.swing.JCheckBox ckbFullArtLands;
private javax.swing.JButton jButton2;
private javax.swing.JLabel lblForest;
private javax.swing.JLabel lblIsland;

View file

@ -41,6 +41,9 @@
<Component id="lblFreeMulligans" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="spnFreeMulligans" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="chkSpectatorsAllowed" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="txtName" min="-2" pref="178" max="-2" attributes="0"/>
@ -152,6 +155,7 @@
<Component id="spnFreeMulligans" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblFreeMulligans" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="chkSpectatorsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cbGameType" alignment="3" min="-2" max="-2" attributes="0"/>
@ -274,6 +278,13 @@
<Property name="toolTipText" type="java.lang.String" value="The number of mulligans a player can use without decreasing the number of drawn cards."/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="chkSpectatorsAllowed">
<Properties>
<Property name="text" type="java.lang.String" value="Spectators allowed"/>
<Property name="toolTipText" type="java.lang.String" value="Allow spectators to view your game."/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="spnFreeMulligans">
</Component>
<Component class="javax.swing.JLabel" name="lblNumPlayers">

View file

@ -102,6 +102,7 @@ public class NewTableDialog extends MageDialog {
lblGameType = new javax.swing.JLabel();
cbGameType = new javax.swing.JComboBox();
chkRollbackTurnsAllowed = new javax.swing.JCheckBox();
chkSpectatorsAllowed = new javax.swing.JCheckBox();
chkRated = new javax.swing.JCheckBox();
lblFreeMulligans = new javax.swing.JLabel();
spnFreeMulligans = new javax.swing.JSpinner();
@ -151,6 +152,9 @@ public class NewTableDialog extends MageDialog {
chkRollbackTurnsAllowed.setText("Allow rollbacks");
chkRollbackTurnsAllowed.setToolTipText("<HTML>Allow to rollback to the start of previous turns<br>\nif all players agree.\n");
chkSpectatorsAllowed.setText("Allow Spectators");
chkSpectatorsAllowed.setToolTipText("<HTML>Allow spectators to watch.\n");
chkRated.setText("Rated");
chkRated.setToolTipText("Indicates if matches will be rated.");
@ -231,7 +235,9 @@ public class NewTableDialog extends MageDialog {
.addGap(13, 13, 13)
.addComponent(lblFreeMulligans)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(13, 13, 13)
.addComponent(chkSpectatorsAllowed))
.addGroup(layout.createSequentialGroup()
.addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -325,7 +331,8 @@ public class NewTableDialog extends MageDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblFreeMulligans)
.addComponent(chkRollbackTurnsAllowed))
.addComponent(chkRollbackTurnsAllowed)
.addComponent(chkSpectatorsAllowed))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblGameType)))
@ -401,6 +408,7 @@ public class NewTableDialog extends MageDialog {
options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem());
options.setWinsNeeded((Integer) this.spnNumWins.getValue());
options.setRollbackTurnsAllowed(chkRollbackTurnsAllowed.isSelected());
options.setSpectatorsAllowed(chkSpectatorsAllowed.isSelected());
options.setRated(chkRated.isSelected());
options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue());
options.setPassword(this.txtPassword.getText());
@ -658,6 +666,7 @@ public class NewTableDialog extends MageDialog {
}
this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_WINS + versionStr, "2")));
this.chkRollbackTurnsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED + versionStr, "Yes").equals("Yes"));
this.chkSpectatorsAllowed.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, "Yes").equals("Yes"));
this.chkRated.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RATED + versionStr, "No").equals("Yes"));
this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, "0")));
@ -739,6 +748,7 @@ public class NewTableDialog extends MageDialog {
private javax.swing.JComboBox cbSkillLevel;
private javax.swing.JComboBox cbTimeLimit;
private javax.swing.JCheckBox chkRollbackTurnsAllowed;
private javax.swing.JCheckBox chkSpectatorsAllowed;
private javax.swing.JCheckBox chkRated;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;

View file

@ -25,17 +25,18 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="saveButton" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="exitButton" min="-2" pref="100" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Component id="tabsPanel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="saveButton" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="exitButton" min="-2" pref="100" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="tabsPanel" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -94,10 +95,10 @@
<EmptySpace max="-2" attributes="0"/>
<Component id="main_game" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="main_gamelog" min="-2" max="-2" attributes="0"/>
<Component id="main_gamelog" min="-2" pref="107" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="main_battlefield" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="154" max="32767" attributes="0"/>
<EmptySpace pref="121" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -121,9 +122,10 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="cbDraftLogAutoSave" max="32767" attributes="0"/>
<Component id="cbGameLogAutoSave" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="cbDraftLogAutoSave" min="-2" max="-2" attributes="0"/>
<Component id="cbGameJsonLogAutoSave" min="-2" max="-2" attributes="0"/>
<Component id="cbGameLogAutoSave" alignment="0" min="-2" pref="505" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
@ -134,7 +136,10 @@
<Group type="102" attributes="0">
<Component id="cbGameLogAutoSave" alignment="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbDraftLogAutoSave" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="cbDraftLogAutoSave" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cbGameJsonLogAutoSave" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -143,7 +148,7 @@
<Component class="javax.swing.JCheckBox" name="cbGameLogAutoSave">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Auto save game logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/>
<Property name="text" type="java.lang.String" value="Save game logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/>
<Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/>
</Properties>
<Events>
@ -153,13 +158,23 @@
<Component class="javax.swing.JCheckBox" name="cbDraftLogAutoSave">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Auto save draft logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/>
<Property name="text" type="java.lang.String" value="Save draft logs (to &quot;../Mage.Client/gamelogs/&quot; directory)"/>
<Property name="toolTipText" type="java.lang.String" value="The logs of all your games will be saved to the mentioned folder if this option is switched on."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDraftLogAutoSaveActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="cbGameJsonLogAutoSave">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Save JSON game logs (to &quot;../Mage.Client/gamelogsJson/&quot; directory)"/>
<Property name="toolTipText" type="java.lang.String" value="The JSON logs of all your games will be saved to the mentioned folder if this option is switched on."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbGameJsonLogAutoSaveActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="main_card">
@ -221,7 +236,7 @@
<Property name="toolTipText" type="java.lang.String" value="Write the card&apos;s name on the card to make the card name more recognizable."/>
<Property name="actionCommand" type="java.lang.String" value=""/>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
<Color id="Standardcursor"/>
</Property>
</Properties>
<Events>
@ -252,7 +267,7 @@
<Property name="selected" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" value="Show the path Xmage is expecting for this card&apos;s image (only displays if missing)"/>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
<Color id="Standardcursor"/>
</Property>
<Property name="label" type="java.lang.String" value="Display image path for missing images"/>
</Properties>
@ -289,7 +304,7 @@
<Component id="cbAskMoveToGraveOrder" alignment="0" max="32767" attributes="0"/>
<Component id="showAbilityPickerForced" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace pref="255" max="32767" attributes="0"/>
<EmptySpace pref="177" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -4318,7 +4333,7 @@
</Group>
<Component id="cbUseDefaultImageFolder" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="270" max="32767" attributes="0"/>
<EmptySpace min="0" pref="308" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
@ -5743,7 +5758,7 @@
<Component id="jLabel17" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace pref="198" max="32767" attributes="0"/>
<EmptySpace pref="201" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -6008,7 +6023,7 @@
<Component id="keyToggleRecordMacro" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="controlsDescriptionLabel" pref="441" max="32767" attributes="0"/>
<Component id="controlsDescriptionLabel" pref="478" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>

View file

@ -65,12 +65,11 @@ import javax.swing.filechooser.FileFilter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.components.KeyBindButton;
import static mage.client.constants.Constants.BATTLEFIELD_FEEDBACK_COLORIZING_MODE_ENABLE_BY_MULTICOLOR;
import mage.client.util.Config;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageHelper;
import mage.client.util.gui.BufferedImageBuilder;
import static mage.client.constants.Constants.BATTLEFIELD_FEEDBACK_COLORIZING_MODE_ENABLE_BY_MULTICOLOR;
import static mage.constants.Constants.DEFAULT_AVATAR_ID;
import static mage.constants.Constants.MAX_AVATAR_ID;
import static mage.constants.Constants.MIN_AVATAR_ID;
@ -79,6 +78,7 @@ import mage.players.net.UserGroup;
import mage.players.net.UserSkipPrioritySteps;
import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
import mage.remote.Session;
import mage.view.UserRequestMessage;
import org.apache.log4j.Logger;
@ -122,6 +122,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave";
public static final String KEY_DRAFT_LOG_AUTO_SAVE = "draftLogAutoSave";
public static final String KEY_JSON_GAME_LOG_AUTO_SAVE = "gameLogJsonAutoSave";
public static final String KEY_CARD_IMAGES_USE_DEFAULT = "cardImagesUseDefault";
public static final String KEY_CARD_IMAGES_PATH = "cardImagesPath";
@ -191,6 +192,11 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_DECK_EDITOR_LAST_SORT = "deckEditorLastSort";
public static final String KEY_DECK_EDITOR_LAST_SEPARATE_CREATURES = "deckEditorLastSeparateCreatures";
public static final String KEY_DECK_EDITOR_SEARCH_NAMES = "deckEditorSearchNames";
public static final String KEY_DECK_EDITOR_SEARCH_TYPES = "deckEditorSearchTypes";
public static final String KEY_DECK_EDITOR_SEARCH_RULES = "deckEditorSearchRules";
public static final String KEY_DECK_EDITOR_SEARCH_UNIQUE = "deckEditorSearchUnique";
// positions of divider bars
public static final String KEY_TABLES_DIVIDER_LOCATION_1 = "tablePanelDividerLocation1";
public static final String KEY_TABLES_DIVIDER_LOCATION_2 = "tablePanelDividerLocation2";
@ -229,6 +235,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType";
public static final String KEY_NEW_TABLE_NUMBER_OF_WINS = "newTableNumberOfWins";
public static final String KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED = "newTableRollbackTurnsAllowed";
public static final String KEY_NEW_TABLE_SPECTATORS_ALLOWED = "newTableSpectatorsAllowed";
public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans";
public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile";
public static final String KEY_NEW_TABLE_RANGE = "newTableRange";
@ -405,6 +412,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_gamelog = new javax.swing.JPanel();
cbGameLogAutoSave = new javax.swing.JCheckBox();
cbDraftLogAutoSave = new javax.swing.JCheckBox();
cbGameJsonLogAutoSave = new javax.swing.JCheckBox();
main_card = new javax.swing.JPanel();
showCardName = new javax.swing.JCheckBox();
tooltipDelayLabel = new javax.swing.JLabel();
@ -599,7 +607,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_gamelog.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game log"));
cbGameLogAutoSave.setSelected(true);
cbGameLogAutoSave.setText("Auto save game logs (to \"../Mage.Client/gamelogs/\" directory)");
cbGameLogAutoSave.setText("Save game logs (to \"../Mage.Client/gamelogs/\" directory)");
cbGameLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on.");
cbGameLogAutoSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -608,7 +616,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
});
cbDraftLogAutoSave.setSelected(true);
cbDraftLogAutoSave.setText("Auto save draft logs (to \"../Mage.Client/gamelogs/\" directory)");
cbDraftLogAutoSave.setText("Save draft logs (to \"../Mage.Client/gamelogs/\" directory)");
cbDraftLogAutoSave.setToolTipText("The logs of all your games will be saved to the mentioned folder if this option is switched on.");
cbDraftLogAutoSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -616,15 +624,25 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
});
cbGameJsonLogAutoSave.setSelected(true);
cbGameJsonLogAutoSave.setText("Save JSON game logs (to \"../Mage.Client/gamelogsJson/\" directory)");
cbGameJsonLogAutoSave.setToolTipText("The JSON logs of all your games will be saved to the mentioned folder if this option is switched on.");
cbGameJsonLogAutoSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cbGameJsonLogAutoSaveActionPerformed(evt);
}
});
org.jdesktop.layout.GroupLayout main_gamelogLayout = new org.jdesktop.layout.GroupLayout(main_gamelog);
main_gamelog.setLayout(main_gamelogLayout);
main_gamelogLayout.setHorizontalGroup(
main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_gamelogLayout.createSequentialGroup()
.addContainerGap()
.add(main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(cbDraftLogAutoSave, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbGameLogAutoSave, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(cbDraftLogAutoSave)
.add(cbGameJsonLogAutoSave)
.add(cbGameLogAutoSave, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 505, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
main_gamelogLayout.setVerticalGroup(
@ -632,7 +650,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(main_gamelogLayout.createSequentialGroup()
.add(cbGameLogAutoSave)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbDraftLogAutoSave))
.add(cbDraftLogAutoSave)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbGameJsonLogAutoSave)
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
main_card.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card"));
@ -784,7 +805,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(255, Short.MAX_VALUE))
.addContainerGap(177, Short.MAX_VALUE))
);
main_gameLayout.setVerticalGroup(
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -859,10 +880,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 107, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(154, Short.MAX_VALUE))
.addContainerGap(121, Short.MAX_VALUE))
);
main_card.getAccessibleContext().setAccessibleName("Game panel");
@ -1581,7 +1602,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
.add(cbUseDefaultImageFolder))
.add(0, 270, Short.MAX_VALUE)))
.add(0, 308, Short.MAX_VALUE)))
.addContainerGap())
);
panelCardImagesLayout.setVerticalGroup(
@ -2386,7 +2407,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(connection_serversLayout.createSequentialGroup()
.add(141, 141, 141)
.add(jLabel17)))
.addContainerGap(198, Short.MAX_VALUE))
.addContainerGap(201, Short.MAX_VALUE))
);
connection_serversLayout.setVerticalGroup(
connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -2625,7 +2646,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(keyToggleRecordMacro, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 441, Short.MAX_VALUE)))
.add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE)))
.addContainerGap())
);
tabControlsLayout.setVerticalGroup(
@ -2707,16 +2728,16 @@ public class PreferencesDialog extends javax.swing.JDialog {
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(6, 6, 6))
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
.add(org.jdesktop.layout.GroupLayout.LEADING, tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(layout.createSequentialGroup()
.add(0, 0, Short.MAX_VALUE)
.add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
.add(6, 6, 6))
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -2748,6 +2769,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbGameJsonLogAutoSave, KEY_JSON_GAME_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY);
String paramName = KEY_BATTLEFIELD_FEEDBACK_COLORIZING_MODE;
int paramValue = dialog.cbBattlefieldFeedbackColorizingMode.getSelectedIndex();
@ -3193,9 +3215,16 @@ public class PreferencesDialog extends javax.swing.JDialog {
}//GEN-LAST:event_showFullImagePathActionPerformed
private void cbBattlefieldFeedbackColorizingModeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbBattlefieldFeedbackColorizingModeActionPerformed
}//GEN-LAST:event_cbBattlefieldFeedbackColorizingModeActionPerformed
private void cbGameJsonLogAutoSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbGameJsonLogAutoSaveActionPerformed
Session session = SessionHandler.getSession();
if (session != null) {
session.setJsonLogActive(cbGameJsonLogAutoSave.isSelected());
}
}//GEN-LAST:event_cbGameJsonLogAutoSaveActionPerformed
private void showProxySettings() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
switch (proxyType) {
@ -3310,6 +3339,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
load(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true");
load(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true");
load(prefs, dialog.cbGameJsonLogAutoSave, KEY_JSON_GAME_LOG_AUTO_SAVE, "true", "false");
String feedbackParam = "";
try {
@ -3864,6 +3894,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
private javax.swing.JCheckBox cbEnableGameSounds;
private javax.swing.JCheckBox cbEnableOtherSounds;
private javax.swing.JCheckBox cbEnableSkipButtonsSounds;
private javax.swing.JCheckBox cbGameJsonLogAutoSave;
private javax.swing.JCheckBox cbGameLogAutoSave;
private javax.swing.JComboBox cbNumberOfDownloadThreads;
private javax.swing.JCheckBox cbPassPriorityActivation;

View file

@ -47,6 +47,8 @@ import mage.client.util.audio.AudioManager;
import mage.client.util.object.SaveObjectUtil;
import mage.interfaces.callback.CallbackClient;
import mage.interfaces.callback.ClientCallback;
import mage.remote.ActionData;
import mage.remote.Session;
import mage.utils.CompressUtil;
import mage.view.*;
import mage.view.ChatMessage.MessageType;
@ -102,7 +104,6 @@ public class CallbackClientImpl implements CallbackClient {
break;
case CHATMESSAGE: {
ChatMessage message = (ChatMessage) callback.getData();
// Drop messages from ignored users
if (message.getUsername() != null && IgnoreList.IGNORED_MESSAGE_TYPES.contains(message.getMessageType())) {
final String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> "");
@ -183,6 +184,7 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_INIT: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_INIT", callback.getObjectId(), (GameView) callback.getData());
panel.init((GameView) callback.getData());
}
break;
@ -190,6 +192,13 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_OVER: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
Session session = SessionHandler.getSession();
if (session.isJsonLogActive()) {
appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
ActionData actionData = appendJsonEvent("GAME_OVER", callback.getObjectId(), callback.getData());
String logFileName = "game-" + actionData.gameId + ".json";
S3Uploader.upload(logFileName, actionData.gameId.toString());
}
panel.endMessage((String) callback.getData(), callback.getMessageId());
}
break;
@ -201,6 +210,7 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_ASK", callback.getObjectId(), message);
panel.ask(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
}
break;
@ -208,8 +218,10 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_TARGET: // e.g. Pick triggered ability
{
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_TARGET", callback.getObjectId(), message);
panel.pickTarget(message.getMessage(), message.getCardsView(), message.getGameView(),
message.getTargets(), message.isFlag(), message.getOptions(), callback.getMessageId());
}
@ -217,8 +229,10 @@ public class CallbackClientImpl implements CallbackClient {
}
case GAME_SELECT: {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_SELECT", callback.getObjectId(), message);
panel.select(message.getMessage(), message.getGameView(), callback.getMessageId(), message.getOptions());
}
break;
@ -226,6 +240,7 @@ public class CallbackClientImpl implements CallbackClient {
case GAME_CHOOSE_ABILITY: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), callback.getData());
panel.pickAbility((AbilityPickerView) callback.getData());
}
break;
@ -234,15 +249,18 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), message);
panel.pickPile(message.getMessage(), message.getPile1(), message.getPile2());
}
break;
}
case GAME_CHOOSE_CHOICE: {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_CHOOSE_CHOICE", callback.getObjectId(), message);
panel.getChoice(message.getChoice(), callback.getObjectId());
}
break;
@ -251,35 +269,45 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_PLAY_MANA", callback.getObjectId(), message);
panel.playMana(message.getMessage(), message.getGameView(), message.getOptions(), callback.getMessageId());
}
break;
}
case GAME_PLAY_XMANA: {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_PLAY_XMANA", callback.getObjectId(), message);
panel.playXMana(message.getMessage(), message.getGameView(), callback.getMessageId());
}
break;
}
case GAME_GET_AMOUNT: {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_GET_AMOUNT", callback.getObjectId(), message);
panel.getAmount(message.getMin(), message.getMax(), message.getMessage());
}
break;
}
case GAME_UPDATE: {
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData());
panel.updateGame((GameView) callback.getData());
}
break;
}
case END_GAME_INFO:
MageFrame.getInstance().showGameEndDialog((GameEndView) callback.getData());
break;
case SHOW_USERMESSAGE:
List<String> messageData = (List<String>) callback.getData();
@ -293,6 +321,7 @@ public class CallbackClientImpl implements CallbackClient {
GameClientMessage message = (GameClientMessage) callback.getData();
GamePanel panel = MageFrame.getGame(callback.getObjectId());
if (panel != null) {
appendJsonEvent("GAME_INFORM", callback.getObjectId(), message);
panel.inform(message.getMessage(), message.getGameView(), callback.getMessageId());
}
}
@ -376,6 +405,17 @@ public class CallbackClientImpl implements CallbackClient {
});
}
private ActionData appendJsonEvent(String name, UUID gameId, Object value) {
Session session = SessionHandler.getSession();
if (session.isJsonLogActive()) {
ActionData actionData = new ActionData(name, gameId);
actionData.value = value;
session.appendJsonLog(actionData);
return actionData;
}
return null;
}
private void createChatStartMessage(ChatPanelBasic chatPanel) {
chatPanel.setStartMessageDone(true);
ChatPanelBasic usedPanel = chatPanel;

View file

@ -0,0 +1,45 @@
package mage.client.remote;
import com.amazonaws.AmazonClientException;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.Upload;
import java.io.File;
import org.apache.log4j.Logger;
public class S3Uploader {
private static final Logger logger = Logger.getLogger(S3Uploader.class);
public static Boolean upload(String filePath, String keyName) throws Exception {
String existingBucketName = System.getenv("S3_BUCKET") != null ? System.getenv("S3_BUCKET")
: "xmage-game-logs-dev";
String accessKeyId = System.getenv("AWS_ACCESS_ID");
String secretKeyId = System.getenv("AWS_SECRET_KEY");
if (accessKeyId == null || "".equals(accessKeyId)
|| secretKeyId == null || "".equals(secretKeyId)
|| existingBucketName == null || "".equals(existingBucketName)) {
logger.info("Aborting json log sync.");
return false;
}
String path = new File("./" + filePath).getCanonicalPath();
logger.info("Syncing " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKeyId, secretKeyId);
TransferManager tm = new TransferManager(awsCreds);
Upload upload = tm.upload(existingBucketName, "/game/" + keyName + ".json", new File(path));
try {
upload.waitForUploadResult();
logger.info("Sync Complete For " + path + " to bucket: " + existingBucketName + " with AWS Access Id: " + accessKeyId);
new File(path);
return true;
} catch (AmazonClientException amazonClientException) {
logger.fatal("Unable to upload file, upload was aborted.", amazonClientException);
return false;
}
}
}

View file

@ -1444,11 +1444,14 @@ class TableTableModel extends AbstractTableModel {
if (tables[arg0].isTournament()) {
return "Show";
} else {
owner = tables[arg0].getControllerName();
owner = tables[arg0].getControllerName();
if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) {
return "";
}
return "Watch";
if (tables[arg0].getSpectatorsAllowed()) {
return "Watch";
}
return "";
}
default:
return "";

View file

@ -1,6 +1,14 @@
package org.mage.card.arcane;
import java.awt.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageProducer;
@ -18,13 +26,18 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.*;
import mage.cards.repository.ExpansionRepository;
import mage.client.constants.Constants;
import mage.client.constants.Constants.ResourceSetSize;
import mage.client.constants.Constants.ResourceSymbolSize;
import mage.client.util.GUISizeHelper;
import mage.client.util.ImageHelper;
import mage.client.util.gui.BufferedImageBuilder;
@ -36,13 +49,6 @@ import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.util.SVGConstants;
import org.apache.log4j.Logger;
import mage.client.constants.Constants;
import mage.client.constants.Constants.ResourceSymbolSize;
import mage.client.constants.Constants.ResourceSetSize;
import org.jdesktop.swingx.graphics.ShadowRenderer;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.mage.plugins.card.utils.CardImageUtils;
public final class ManaSymbols {
@ -71,9 +77,14 @@ public final class ManaSymbols {
private static final Map<String, Dimension> setImagesExist = new HashMap<>();
private static final Pattern REPLACE_SYMBOLS_PATTERN = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}");
private static String cachedPath;
private static final String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", "B", "BG",
"BR", "G", "GU", "GW", "R", "RG", "RW", "S", "T", "U", "UB", "UR", "W", "WB", "WU",
"WP", "UP", "BP", "RP", "GP", "X", "C", "E"};
private static final String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9",
"B", "BG", "BR", "BP", "2B",
"G", "GU", "GW", "GP", "2G",
"R", "RG", "RW", "RP", "2R",
"S", "T",
"U", "UB", "UR", "UP", "2U",
"W", "WB", "WU", "WP", "2W",
"X", "C", "E"};
private static final JLabel labelRender = new JLabel(); // render mana text
@ -93,22 +104,21 @@ public final class ManaSymbols {
// save symbol images in png for html replacement in texts
// you can add bigger size for better quality
Map<String, BufferedImage> pngImages = manaImages.get(50);
if (pngImages != null){
if (pngImages != null) {
File pngPath = new File(getResourceSymbolsPath(ResourceSymbolSize.PNG));
if (!pngPath.exists()) {
pngPath.mkdirs();
}
for(String symbol: symbols){
try
{
for (String symbol : symbols) {
try {
BufferedImage image = pngImages.get(symbol);
if (image != null){
if (image != null) {
File newFile = new File(pngPath.getPath() + File.separator + symbol + ".png");
ImageIO.write(image, "png", newFile);
}
}catch (Exception e) {
} catch (Exception e) {
LOGGER.warn("Can't generate png image for symbol:" + symbol);
}
}
@ -222,8 +232,7 @@ public final class ManaSymbols {
// load SVG image
// base loader code: https://stackoverflow.com/questions/11435671/how-to-get-a-buffererimage-from-a-svg
// resize code: https://vibranttechie.wordpress.com/2015/05/15/svg-loading-to-javafx-stage-and-auto-scaling-when-stage-resize/
if (useShadow && ((resizeToWidth <= 0) || (resizeToHeight <= 0))){
if (useShadow && ((resizeToWidth <= 0) || (resizeToHeight <= 0))) {
throw new IllegalArgumentException("Must use non zero sizes for shadow.");
}
@ -234,12 +243,12 @@ public final class ManaSymbols {
// These defaults emphasize quality and precision, and
// are more similar to the defaults of other SVG viewers.
// SVG documents can still override these defaults.
String css = "svg {" +
"shape-rendering: geometricPrecision;" +
"text-rendering: geometricPrecision;" +
"color-rendering: optimizeQuality;" +
"image-rendering: optimizeQuality;" +
"}";
String css = "svg {"
+ "shape-rendering: geometricPrecision;"
+ "text-rendering: geometricPrecision;"
+ "color-rendering: optimizeQuality;"
+ "image-rendering: optimizeQuality;"
+ "}";
File cssFile = File.createTempFile("batik-default-override-", ".css");
FileWriter w = new FileWriter(cssFile);
w.write(css);
@ -250,7 +259,7 @@ public final class ManaSymbols {
// resize
int shadowX = 0;
int shadowY = 0;
if(useShadow) {
if (useShadow) {
// shadow size (16px image: 1px left, 2px bottom)
shadowX = 1 * Math.round(1f / 16f * resizeToWidth);
shadowY = 2 * Math.round(1f / 16f * resizeToHeight);
@ -258,11 +267,11 @@ public final class ManaSymbols {
resizeToHeight = resizeToHeight - shadowY;
};
if(resizeToWidth > 0){
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float)resizeToWidth); //your image width
if (resizeToWidth > 0) {
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float) resizeToWidth); //your image width
}
if(resizeToHeight > 0){
transcoderHints.put(ImageTranscoder.KEY_HEIGHT, (float)resizeToHeight); //your image height
if (resizeToHeight > 0) {
transcoderHints.put(ImageTranscoder.KEY_HEIGHT, (float) resizeToHeight); //your image height
}
transcoderHints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE);
@ -293,14 +302,13 @@ public final class ManaSymbols {
t.transcode(input, null);
} catch (Exception e) {
throw new IOException("Couldn't convert svg file: " + svgFile + " , reason: " + e.getMessage());
}
finally {
} finally {
cssFile.delete();
}
BufferedImage originImage = imagePointer[0];
if(useShadow && (originImage.getWidth() > 0)){
if (useShadow && (originImage.getWidth() > 0)) {
// draw shadow
// origin image was reduces in sizes to fit shadow
// see https://stackoverflow.com/a/40833715/1276632
@ -309,10 +317,11 @@ public final class ManaSymbols {
ImageProducer prod = new FilteredImageSource(originImage.getSource(), new RGBImageFilter() {
@Override
public int filterRGB(int x, int y, int rgb) {
if (rgb == 0)
if (rgb == 0) {
return 0;
else
} else {
return 0xff000000;
}
}
});
// create whe black image
@ -325,7 +334,7 @@ public final class ManaSymbols {
// draw original image
g.drawImage(originImage, 0, 0, null);
return result;
}else{
} else {
// return origin image without shadow
return originImage;
}
@ -340,23 +349,22 @@ public final class ManaSymbols {
ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f,
Color.GRAY);
return renderer.createShadow(base);
*/
*/
//imagePointer[0];
}
public static File getSymbolFileNameAsSVG(String symbol){
public static File getSymbolFileNameAsSVG(String symbol) {
return new File(getResourceSymbolsPath(ResourceSymbolSize.SVG) + symbol + ".svg");
}
private static BufferedImage loadSymbolAsSVG(String symbol, int resizeToWidth, int resizeToHeight){
private static BufferedImage loadSymbolAsSVG(String symbol, int resizeToWidth, int resizeToHeight) {
File sourceFile = getSymbolFileNameAsSVG(symbol);
return loadSymbolAsSVG(sourceFile, resizeToWidth, resizeToHeight);
}
private static BufferedImage loadSymbolAsSVG(File sourceFile, int resizeToWidth, int resizeToHeight){
try{
private static BufferedImage loadSymbolAsSVG(File sourceFile, int resizeToWidth, int resizeToHeight) {
try {
// no need to resize svg (lib already do it on load)
return loadSVG(sourceFile, resizeToWidth, resizeToHeight, true);
@ -366,12 +374,12 @@ public final class ManaSymbols {
}
}
private static File getSymbolFileNameAsGIF(String symbol, int size){
private static File getSymbolFileNameAsGIF(String symbol, int size) {
ResourceSymbolSize needSize = null;
if (size <= 15){
if (size <= 15) {
needSize = ResourceSymbolSize.SMALL;
}else if (size <= 25){
} else if (size <= 25) {
needSize = ResourceSymbolSize.MEDIUM;
} else {
needSize = ResourceSymbolSize.LARGE;
@ -380,20 +388,20 @@ public final class ManaSymbols {
return new File(getResourceSymbolsPath(needSize) + symbol + ".gif");
}
private static BufferedImage loadSymbolAsGIF(String symbol, int resizeToWidth, int resizeToHeight){
private static BufferedImage loadSymbolAsGIF(String symbol, int resizeToWidth, int resizeToHeight) {
File file = getSymbolFileNameAsGIF(symbol, resizeToWidth);
return loadSymbolAsGIF(file, resizeToWidth, resizeToHeight);
}
private static BufferedImage loadSymbolAsGIF(File sourceFile, int resizeToWidth, int resizeToHeight){
private static BufferedImage loadSymbolAsGIF(File sourceFile, int resizeToWidth, int resizeToHeight) {
BufferedImage image = null;
try {
if ((resizeToWidth == 15) || (resizeToWidth == 25)){
if ((resizeToWidth == 15) || (resizeToWidth == 25)) {
// normal size
image = ImageIO.read(sourceFile);
}else{
} else {
// resize size
image = ImageIO.read(sourceFile);
@ -407,7 +415,7 @@ public final class ManaSymbols {
return null;
}
return image;
return image;
}
private static boolean loadSymbolImages(int size) {
@ -454,7 +462,7 @@ public final class ManaSymbols {
private static void renameSymbols(String path) {
File file = new File(path);
if (!file.exists()){
if (!file.exists()) {
return;
}
@ -475,7 +483,7 @@ public final class ManaSymbols {
}
}
private static String getResourceSymbolsPath(ResourceSymbolSize needSize){
private static String getResourceSymbolsPath(ResourceSymbolSize needSize) {
// return real path to symbols (default or user defined)
String path = CardImageUtils.getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS + File.separator;
@ -503,15 +511,14 @@ public final class ManaSymbols {
}
// fix double separator if size folder is not set
while(path.endsWith(File.separator))
{
while (path.endsWith(File.separator)) {
path = path.substring(0, path.length() - 1);
}
return path + File.separator;
}
private static String getResourceSetsPath(ResourceSetSize needSize){
private static String getResourceSetsPath(ResourceSetSize needSize) {
// return real path to sets icons (default or user defined)
String path = CardImageUtils.getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS + File.separator;
@ -533,8 +540,7 @@ public final class ManaSymbols {
}
// fix double separator if size folder is not set
while(path.endsWith(File.separator))
{
while (path.endsWith(File.separator)) {
path = path.substring(0, path.length() - 1);
}
@ -592,10 +598,7 @@ public final class ManaSymbols {
Graphics2D gg = image.createGraphics();
manaPanel.paint(gg);
g.drawImage(image, x, y, null);
*/
*/
// OLD version with custom draw
Map<String, BufferedImage> sizedSymbols = manaImages.get(symbolWidth);
if (manaCost.isEmpty()) {
@ -627,8 +630,8 @@ public final class ManaSymbols {
int stringWidth = labelRender.getFontMetrics(labelFont).stringWidth(labelText);
int componentWidth = labelRender.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
double widthRatio = (double) componentWidth / (double) stringWidth;
int newFontSize = (int) (labelFont.getSize() * widthRatio);
int componentHeight = labelRender.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
@ -638,11 +641,11 @@ public final class ManaSymbols {
// render component to new position
// need to copy graphics, overvise it draw at top left corner
// https://stackoverflow.com/questions/4974268/java-paint-problem
Graphics2D labelG = (Graphics2D)g.create(x, y, symbolWidth, symbolWidth);
Graphics2D labelG = (Graphics2D) g.create(x, y, symbolWidth, symbolWidth);
labelG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
labelG.fillOval(x + 1, y + 1, symbolWidth - 2, symbolWidth - 2);
labelRender.paint(labelG);
}else {
} else {
// ICON draw
g.drawImage(image, x, y, null);
}
@ -666,12 +669,12 @@ public final class ManaSymbols {
TOOLTIP,
}
private static String filePathToUrl(String path){
private static String filePathToUrl(String path) {
// convert file path to uri path (for html docs)
if((path != null) && (!path.equals(""))){
if ((path != null) && (!path.equals(""))) {
File file = new File(path);
return file.toURI().toString();
}else{
} else {
return null;
}
}
@ -680,7 +683,6 @@ public final class ManaSymbols {
// mana cost to HTML images (urls to files)
// do not use it for new code - try to suppotr svg render
int symbolSize;
switch (type) {
case TABLE:
@ -702,22 +704,20 @@ public final class ManaSymbols {
// auto size
ResourceSymbolSize needSize = null;
if (symbolSize <= 15){
if (symbolSize <= 15) {
needSize = ResourceSymbolSize.SMALL;
}else if (symbolSize <= 25){
} else if (symbolSize <= 25) {
needSize = ResourceSymbolSize.MEDIUM;
} else {
needSize = ResourceSymbolSize.LARGE;
}
// replace every {symbol} to <img> link
// ignore data backup
String replaced = value
.replace("{source}", "|source|")
.replace("{this}", "|this|");
// not need to add different images (width and height do the work)
// use best png size (generated on startup) TODO: add reload images after update
String htmlImagesPath = getResourceSymbolsPath(ResourceSymbolSize.PNG);
@ -725,8 +725,8 @@ public final class ManaSymbols {
.replace("$", "@S@"); // paths with $ will rise error, need escape that
replaced = REPLACE_SYMBOLS_PATTERN.matcher(replaced).replaceAll(
"<img src='" + filePathToUrl(htmlImagesPath) + "$1$2" + ".png' alt='$1$2' width="
+ symbolSize + " height=" + symbolSize + '>');
"<img src='" + filePathToUrl(htmlImagesPath) + "$1$2" + ".png' alt='$1$2' width="
+ symbolSize + " height=" + symbolSize + '>');
// ignore data restore
replaced = replaced
@ -774,4 +774,3 @@ public final class ManaSymbols {
return sizedSymbols.get(symbol);
}
}

View file

@ -9,7 +9,6 @@ import com.google.common.collect.AbstractIterator;
import java.io.File;
import static java.lang.String.format;
import java.util.Iterator;
import mage.client.constants.Constants;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
@ -42,7 +41,7 @@ public class GathererSymbols implements Iterable<DownloadJob> {
public GathererSymbols() {
outDir = new File(getImagesDir() + Constants.RESOURCE_PATH_SYMBOLS);
if (!outDir.exists()){
if (!outDir.exists()) {
outDir.mkdirs();
}
}
@ -76,8 +75,9 @@ public class GathererSymbols implements Iterable<DownloadJob> {
File dst = new File(dir, symbol + ".gif");
/**
* Handle a bug on Gatherer where a few symbols are missing at the large size.
* Fall back to using the medium symbol for those cases.
* Handle a bug on Gatherer where a few symbols are missing
* at the large size. Fall back to using the medium symbol
* for those cases.
*/
int modSizeIndex = sizeIndex;
if (sizeIndex == 2) {
@ -93,7 +93,7 @@ public class GathererSymbols implements Iterable<DownloadJob> {
break;
default:
// Nothing to do, symbol is available in the large size
// Nothing to do, symbol is available in the large size
}
}

View file

@ -268,7 +268,7 @@ public enum WizardCardsImageSource implements CardImageSource {
supportedSets.add("V17"); // From the Vault: Transform
supportedSets.add("UST"); // Unstable
supportedSets.add("RIX"); // Rivals of Ixalan
// supportedSets.add("A25"); // Masters 25
supportedSets.add("A25"); // Masters 25
// supportedSets.add("DOM"); // Dominaria
// supportedSets.add("M19"); // Core 2019

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<artifactId>mage-common</artifactId>
@ -25,6 +25,7 @@
<artifactId>jspf-core</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.jboss.remoting</groupId>
<artifactId>jboss-remoting</artifactId>
@ -50,7 +51,11 @@
<artifactId>trove</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
<!-- to get the reference to local repository with com\googlecode\jspf\jspf-core\0.9.1\ -->
<repositories>

View file

@ -0,0 +1,138 @@
/*
* Copyright 2018 nanarpuss_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.remote;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import java.util.UUID;
public class ActionData {
@Expose
public UUID gameId;
@Expose
public String sessionId;
@Expose
public String type;
@Expose
public Object value;
@Expose
public String message;
public String toJson() {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.setExclusionStrategies(new CustomExclusionStrategy()).create();
return gson.toJson(this);
}
public ActionData(String type, UUID gameId, String sessionId) {
this.type = type;
this.sessionId = sessionId;
this.gameId = gameId;
}
public ActionData(String type, UUID gameId) {
this.type = type;
this.gameId = gameId;
}
public class CustomExclusionStrategy implements ExclusionStrategy {
// FIXME: Very crude way of whitelisting, as it applies to all levels of the JSON tree.
private final java.util.Set<String> KEEP = new java.util.HashSet<>(
java.util.Arrays.asList(
new String[]{
"id",
"choice",
"damage",
"abilityType",
"ability",
"abilities",
"method",
"data",
"options",
"life",
"players",
"zone",
"step",
"phase",
"attackers",
"blockers",
"tapped",
"damage",
"combat",
"paid",
"hand",
"stack",
"convertedManaCost",
"gameId",
"canPlayInHand",
"gameView",
"sessionId",
"power",
"choices",
"targets",
"loyalty",
"toughness",
"power",
"type",
"priorityTime",
"manaCost",
"value",
"message",
"cardsView",
"name",
"count",
"counters",
"battlefield",
"parentId"
}));
public CustomExclusionStrategy() {
}
// This method is called for all fields. if the method returns true the
// field is excluded from serialization
@Override
public boolean shouldSkipField(FieldAttributes f) {
String name = f.getName();
return !KEEP.contains(name);
}
// This method is called for all classes. If the method returns true the
// class is excluded.
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}
}

View file

@ -24,8 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
*/
package mage.remote;
import mage.remote.interfaces.ChatSession;
@ -46,4 +45,5 @@ import mage.remote.interfaces.Testable;
*/
public interface Session extends ClientData, Connect, GamePlay, GameTypes, ServerState, ChatSession, Feedback, PlayerActions, Replays, Testable {
public void appendJsonLog(ActionData actionData);
}

View file

@ -27,7 +27,11 @@
*/
package mage.remote;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.util.*;
@ -86,6 +90,7 @@ public class SessionImpl implements Session {
private static boolean debugMode = false;
private boolean canceled = false;
private boolean jsonLogActive = false;
static {
debugMode = System.getProperty("debug.mage") != null;
@ -798,6 +803,9 @@ public class SessionImpl implements Session {
public boolean sendPlayerUUID(UUID gameId, UUID data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_UUID", gameId, getSessionId());
actionData.value = data;
appendJsonLog(actionData);
server.sendPlayerUUID(gameId, sessionId, data);
return true;
}
@ -813,6 +821,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerBoolean(UUID gameId, boolean data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_BOOLEAN", gameId, getSessionId());
actionData.value = data;
appendJsonLog(actionData);
server.sendPlayerBoolean(gameId, sessionId, data);
return true;
}
@ -828,6 +840,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerInteger(UUID gameId, int data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_INTEGER", gameId, getSessionId());
actionData.value = data;
appendJsonLog(actionData);
server.sendPlayerInteger(gameId, sessionId, data);
return true;
}
@ -843,6 +859,10 @@ public class SessionImpl implements Session {
public boolean sendPlayerString(UUID gameId, String data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_STRING", gameId, getSessionId());
actionData.value = data;
appendJsonLog(actionData);
server.sendPlayerString(gameId, sessionId, data);
return true;
}
@ -858,6 +878,9 @@ public class SessionImpl implements Session {
public boolean sendPlayerManaType(UUID gameId, UUID playerId, ManaType data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_MANA_TYPE", gameId, getSessionId());
actionData.value = data;
appendJsonLog(actionData);
server.sendPlayerManaType(gameId, playerId, sessionId, data);
return true;
}
@ -869,6 +892,25 @@ public class SessionImpl implements Session {
return false;
}
@Override
public void appendJsonLog(ActionData actionData) {
if (isJsonLogActive()) {
String dir = "gamelogsJson";
File saveDir = new File(dir);
//Existence check
if (!saveDir.exists()) {
saveDir.mkdirs();
}
actionData.sessionId = getSessionId();
String logFileName = dir + File.separator + "game-" + actionData.gameId + ".json";
try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(logFileName, true)))) {
out.println(actionData.toJson());
} catch (IOException e) {
logger.error("Cant write JSON game log file - " + logFileName, e);
}
}
}
@Override
public DraftPickView sendCardPick(UUID draftId, UUID cardId, Set<UUID> hiddenCards) {
try {
@ -1274,6 +1316,11 @@ public class SessionImpl implements Session {
public boolean sendPlayerAction(PlayerAction passPriorityAction, UUID gameId, Object data) {
try {
if (isConnected()) {
ActionData actionData = new ActionData("SEND_PLAYER_ACTION", gameId, getSessionId());
actionData.value = passPriorityAction + (data != null ? " " + data.toString() : "");
appendJsonLog(actionData);
server.sendPlayerAction(passPriorityAction, gameId, sessionId, data);
return true;
}
@ -1597,6 +1644,16 @@ public class SessionImpl implements Session {
}
}
@Override
public boolean isJsonLogActive() {
return jsonLogActive;
}
@Override
public void setJsonLogActive(boolean jsonLogActive) {
this.jsonLogActive = jsonLogActive;
}
}
class MageAuthenticator extends Authenticator {

View file

@ -37,4 +37,8 @@ public interface ClientData {
String getUserName();
boolean updatePreferencesForServer(UserData userData);
void setJsonLogActive(boolean active);
boolean isJsonLogActive();
}

View file

@ -40,8 +40,8 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
*/
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 27;
public final static String MAGE_VERSION_MINOR_PATCH = "V4";
public final static int MAGE_VERSION_PATCH = 28;
public final static String MAGE_VERSION_MINOR_PATCH = "V0";
public final static String MAGE_VERSION_INFO = "";
private final int major;

View file

@ -53,6 +53,8 @@ import mage.target.Target;
import mage.target.Targets;
import mage.util.SubTypeList;
import com.google.gson.annotations.Expose;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -61,11 +63,17 @@ public class CardView extends SimpleCardView {
private static final long serialVersionUID = 1L;
protected UUID parentId;
@Expose
protected String name;
@Expose
protected String displayName;
@Expose
protected List<String> rules;
@Expose
protected String power;
@Expose
protected String toughness;
@Expose
protected String loyalty = "";
protected String startingLoyalty;
protected EnumSet<CardType> cardTypes;
@ -110,7 +118,6 @@ public class CardView extends SimpleCardView {
protected ArtRect artRect = ArtRect.NORMAL;
protected List<UUID> targets;
protected UUID pairedCard;
protected List<UUID> bandedCards;
protected boolean paid;

View file

@ -32,6 +32,11 @@ import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import mage.choices.Choice;
/**
@ -39,18 +44,29 @@ import mage.choices.Choice;
* @author BetaSteward_at_googlemail.com
*/
public class GameClientMessage implements Serializable {
@Expose
private static final long serialVersionUID = 1L;
@Expose
private GameView gameView;
@Expose
private CardsView cardsView;
@Expose
private CardsView cardsView2;
@Expose
private String message;
@Expose
private boolean flag;
@Expose
private String[] strings;
@Expose
private Set<UUID> targets;
@Expose
private int min;
@Expose
private int max;
@Expose
private Map<String, Serializable> options;
@Expose
private Choice choice;
public GameClientMessage(GameView gameView) {
@ -155,4 +171,11 @@ public class GameClientMessage implements Serializable {
return choice;
}
public String toJson() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
return gson.toJson(this);
}
}

View file

@ -28,11 +28,17 @@
package mage.view;
import java.io.Serializable;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.costs.Cost;
import mage.cards.Card;
@ -54,6 +60,8 @@ import mage.game.stack.StackObject;
import mage.players.Player;
import mage.watchers.common.CastSpellLastTurnWatcher;
import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
*
@ -64,7 +72,6 @@ public class GameView implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(GameView.class);
private final int priorityTime;
private final List<PlayerView> players = new ArrayList<>();
private CardsView hand;
@ -351,4 +358,8 @@ public class GameView implements Serializable {
return rollbackTurnsAllowed;
}
public String toJson() {
Gson gson = new GsonBuilder().create();
return gson.toJson(this);
}
}

View file

@ -28,6 +28,8 @@
package mage.view;
import com.google.gson.annotations.Expose;
import java.io.Serializable;
import java.util.UUID;
@ -36,6 +38,7 @@ import java.util.UUID;
* @author BetaSteward_at_googlemail.com
*/
public class SimpleCardView implements Serializable {
@Expose
protected UUID id;
protected String expansionSetCode;
protected String tokenSetCode;

View file

@ -65,6 +65,7 @@ public class TableView implements Serializable {
private final boolean limited;
private final boolean rated;
private final boolean passworded;
private final boolean spectatorsAllowed;
public TableView(Table table) {
this.tableId = table.getId();
@ -139,6 +140,7 @@ public class TableView implements Serializable {
this.limited = table.getMatch().getOptions().isLimited();
this.rated = table.getMatch().getOptions().isRated();
this.passworded = !table.getMatch().getOptions().getPassword().isEmpty();
this.spectatorsAllowed = table.getMatch().getOptions().isSpectatorsAllowed();
} else {
// TOURNAMENT
if (table.getTournament().getOptions().getNumberRounds() > 0) {
@ -186,6 +188,7 @@ public class TableView implements Serializable {
this.limited = table.getTournament().getOptions().getMatchOptions().isLimited();
this.rated = table.getTournament().getOptions().getMatchOptions().isRated();
this.passworded = !table.getTournament().getOptions().getPassword().isEmpty();
this.spectatorsAllowed = table.getTournament().getOptions().isWatchingAllowed();
}
}
@ -200,6 +203,11 @@ public class TableView implements Serializable {
public String getControllerName() {
return controllerName;
}
public boolean getSpectatorsAllowed() {
return spectatorsAllowed;
}
public String getGameType() {
return gameType;

View file

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

View file

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

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<groupId>org.mage</groupId>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -522,7 +522,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
continue;
}
if (!sim.checkIfGameIsOver()
&& action.isUsesStack()) {
&& (action.isUsesStack() || action instanceof PassAbility)) {
// only pass if the last action uses the stack
UUID nextPlayerId = sim.getPlayerList().get();
do {
@ -533,8 +533,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
SimulationNode2 newNode = new SimulationNode2(node, sim, action, depth, currentPlayer.getId());
sim.checkStateAndTriggered();
int val;
if (action instanceof PassAbility) {
// Stop to simulate deeper if PassAbility
if (action instanceof PassAbility && sim.getStack().isEmpty()) {
// Stop to simulate deeper if PassAbility and stack is empty
val = GameStateEvaluator2.evaluate(this.getId(), sim);
} else {
val = addActions(newNode, depth - 1, alpha, beta);

View file

@ -109,6 +109,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
}
return false;
case DECLARE_BLOCKERS:
printOutState(game);
if (actions.isEmpty()) {
calculateActions(game);
}
act(game);
return true;
case FIRST_COMBAT_DAMAGE:
case COMBAT_DAMAGE:
case END_COMBAT:

View file

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

View file

@ -1312,6 +1312,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (numAvailable < 0) {
numAvailable = 0;
}
if (numAvailable > max) {
numAvailable = max;
}
return numAvailable;
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<artifactId>mage-player-ai-mcts</artifactId>

View file

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

View file

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

View file

@ -1111,11 +1111,13 @@ public class HumanPlayer extends PlayerImpl {
if (object == null) {
return;
}
Spell spell = game.getStack().getSpell(abilityToCast.getSourceId());
if (spell != null && !spell.isResolving()
&& spell.isDoneActivatingManaAbilities()) {
game.informPlayer(this, "You can no longer use activated mana abilities to pay for the current spell. Cancel and recast the spell and activate mana abilities first.");
return;
if (AbilityType.SPELL.equals(abilityToCast.getAbilityType())) {
Spell spell = game.getStack().getSpell(abilityToCast.getSourceId());
if (spell != null && !spell.isResolving()
&& spell.isDoneActivatingManaAbilities()) {
game.informPlayer(this, "You can no longer use activated mana abilities to pay for the current spell. Cancel and recast the spell and activate mana abilities first.");
return;
}
}
Zone zone = game.getState().getZone(object.getId());
if (zone != null) {

View file

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

View file

@ -0,0 +1,641 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
*
* @author LevelX2
*/
public class LegacyCube2018February extends DraftCube {
public LegacyCube2018February() {
super("MTGO Legacy Cube February 2018 (600 cards)");
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", ""));
cubeCards.add(new DraftCube.CardIdentity("Abrade", ""));
cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay", ""));
cubeCards.add(new DraftCube.CardIdentity("Abyssal Persecutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", ""));
cubeCards.add(new DraftCube.CardIdentity("Act of Aggression", ""));
cubeCards.add(new DraftCube.CardIdentity("Adanto Vanguard", ""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Goldmane", ""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", ""));
cubeCards.add(new DraftCube.CardIdentity("Anafenza, Kin-Tree Spirit", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Invention", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity", ""));
cubeCards.add(new DraftCube.CardIdentity("Anger of the Gods", ""));
cubeCards.add(new DraftCube.CardIdentity("Anguished Unmaking", ""));
cubeCards.add(new DraftCube.CardIdentity("Animate Dead", ""));
cubeCards.add(new DraftCube.CardIdentity("Approach of the Second Sun", ""));
cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Arc Trail", ""));
cubeCards.add(new DraftCube.CardIdentity("Archangel Avacyn", ""));
cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", ""));
cubeCards.add(new DraftCube.CardIdentity("Armageddon", ""));
cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Assemble the Legion", ""));
cubeCards.add(new DraftCube.CardIdentity("Augur of Bolas", ""));
cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim", ""));
cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders", ""));
cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Badlands", ""));
cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", ""));
cubeCards.add(new DraftCube.CardIdentity("Banefire", ""));
cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Banisher Priest", ""));
cubeCards.add(new DraftCube.CardIdentity("Banishing Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Baral, Chief of Compliance", ""));
cubeCards.add(new DraftCube.CardIdentity("Batterskull", ""));
cubeCards.add(new DraftCube.CardIdentity("Bayou", ""));
cubeCards.add(new DraftCube.CardIdentity("Beast Within", ""));
cubeCards.add(new DraftCube.CardIdentity("Bedlam Reveler", ""));
cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", ""));
cubeCards.add(new DraftCube.CardIdentity("Birthing Pod", ""));
cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", ""));
cubeCards.add(new DraftCube.CardIdentity("Blackcleave Cliffs", ""));
cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", ""));
cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodghast", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloom Tender", ""));
cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", ""));
cubeCards.add(new DraftCube.CardIdentity("Bogardan Hellkite", ""));
cubeCards.add(new DraftCube.CardIdentity("Bomat Courier", ""));
cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", ""));
cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", ""));
cubeCards.add(new DraftCube.CardIdentity("Boros Charm", ""));
cubeCards.add(new DraftCube.CardIdentity("Boros Reckoner", ""));
cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new DraftCube.CardIdentity("Brainstorm", ""));
cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", ""));
cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", ""));
cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley", ""));
cubeCards.add(new DraftCube.CardIdentity("Bruna, the Fading Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Buried Alive", ""));
cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Careful Consideration", ""));
cubeCards.add(new DraftCube.CardIdentity("Careful Study", ""));
cubeCards.add(new DraftCube.CardIdentity("Carnage Tyrant", ""));
cubeCards.add(new DraftCube.CardIdentity("Cathartic Reunion", ""));
cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", ""));
cubeCards.add(new DraftCube.CardIdentity("Censor", ""));
cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Chainer's Edict", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra's Phoenix", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Fire of Kaladesh", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Flamecaller", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", ""));
cubeCards.add(new DraftCube.CardIdentity("Char", ""));
cubeCards.add(new DraftCube.CardIdentity("Chart a Course", ""));
cubeCards.add(new DraftCube.CardIdentity("Chord of Calling", ""));
cubeCards.add(new DraftCube.CardIdentity("Chromatic Lantern", ""));
cubeCards.add(new DraftCube.CardIdentity("City of Brass", ""));
cubeCards.add(new DraftCube.CardIdentity("Clifftop Retreat", ""));
cubeCards.add(new DraftCube.CardIdentity("Cloudgoat Ranger", ""));
cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", ""));
cubeCards.add(new DraftCube.CardIdentity("Coldsteel Heart", ""));
cubeCards.add(new DraftCube.CardIdentity("Collective Brutality", ""));
cubeCards.add(new DraftCube.CardIdentity("Collective Defiance", ""));
cubeCards.add(new DraftCube.CardIdentity("Collective Effort", ""));
cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", ""));
cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new DraftCube.CardIdentity("Condemn", ""));
cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", ""));
cubeCards.add(new DraftCube.CardIdentity("Control Magic", ""));
cubeCards.add(new DraftCube.CardIdentity("Copperline Gorge", ""));
cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Counterspell", ""));
cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", ""));
cubeCards.add(new DraftCube.CardIdentity("Crater's Claws", ""));
cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", ""));
cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", ""));
cubeCards.add(new DraftCube.CardIdentity("Crux of Fate", ""));
cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Cultivate", ""));
cubeCards.add(new DraftCube.CardIdentity("Cyclonic Rift", ""));
cubeCards.add(new DraftCube.CardIdentity("Damnation", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Petition", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Darkslick Shores", ""));
cubeCards.add(new DraftCube.CardIdentity("Day of Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Daze", ""));
cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Declaration in Stone", ""));
cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets", ""));
cubeCards.add(new DraftCube.CardIdentity("Den Protector", ""));
cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", ""));
cubeCards.add(new DraftCube.CardIdentity("Desecration Demon", ""));
cubeCards.add(new DraftCube.CardIdentity("Devil's Play", ""));
cubeCards.add(new DraftCube.CardIdentity("Devoted Druid", ""));
cubeCards.add(new DraftCube.CardIdentity("Disallow", ""));
cubeCards.add(new DraftCube.CardIdentity("Disfigure", ""));
cubeCards.add(new DraftCube.CardIdentity("Dismember", ""));
cubeCards.add(new DraftCube.CardIdentity("Dismiss", ""));
cubeCards.add(new DraftCube.CardIdentity("Dissipate", ""));
cubeCards.add(new DraftCube.CardIdentity("Dissolve", ""));
cubeCards.add(new DraftCube.CardIdentity("Distended Mindbender", ""));
cubeCards.add(new DraftCube.CardIdentity("Domri Rade", ""));
cubeCards.add(new DraftCube.CardIdentity("Doom Blade", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonskull Summit", ""));
cubeCards.add(new DraftCube.CardIdentity("Drana, Liberator of Malakir", ""));
cubeCards.add(new DraftCube.CardIdentity("Dread Return", ""));
cubeCards.add(new DraftCube.CardIdentity("Dreadbore", ""));
cubeCards.add(new DraftCube.CardIdentity("Dromoka's Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Drowned Catacomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Dualcaster Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Dungeon Geists", ""));
cubeCards.add(new DraftCube.CardIdentity("Duplicant", ""));
cubeCards.add(new DraftCube.CardIdentity("Duress", ""));
cubeCards.add(new DraftCube.CardIdentity("Duskwatch Recruiter", ""));
cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", ""));
cubeCards.add(new DraftCube.CardIdentity("Elder Deep-Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Electrolyze", ""));
cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth Tirel", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", ""));
cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow", ""));
cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Emeria Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", ""));
cubeCards.add(new DraftCube.CardIdentity("Entomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Entreat the Angels", ""));
cubeCards.add(new DraftCube.CardIdentity("Erebos, God of the Dead", ""));
cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", ""));
cubeCards.add(new DraftCube.CardIdentity("Exhume", ""));
cubeCards.add(new DraftCube.CardIdentity("Explore", ""));
cubeCards.add(new DraftCube.CardIdentity("Exquisite Firecraft", ""));
cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", ""));
cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters", ""));
cubeCards.add(new DraftCube.CardIdentity("Falkenrath Gorger", ""));
cubeCards.add(new DraftCube.CardIdentity("Farseek", ""));
cubeCards.add(new DraftCube.CardIdentity("Fatal Push", ""));
cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Fertile Ground", ""));
cubeCards.add(new DraftCube.CardIdentity("Field of Ruin", ""));
cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter", ""));
cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Fire // Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Firebolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Flame Slash", ""));
cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", ""));
cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", ""));
cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", ""));
cubeCards.add(new DraftCube.CardIdentity("Forbid", ""));
cubeCards.add(new DraftCube.CardIdentity("Force of Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Force Spike", ""));
cubeCards.add(new DraftCube.CardIdentity("Forked Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Frost Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Apex Predator", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter", ""));
cubeCards.add(new DraftCube.CardIdentity("Gatekeeper of Malakir", ""));
cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", ""));
cubeCards.add(new DraftCube.CardIdentity("Genesis Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Geralf's Messenger", ""));
cubeCards.add(new DraftCube.CardIdentity("Ghor-Clan Rampager", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon of the Trials", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Gifted Aetherborn", ""));
cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven", ""));
cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus", ""));
cubeCards.add(new DraftCube.CardIdentity("Gisela, the Broken Blade", ""));
cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", ""));
cubeCards.add(new DraftCube.CardIdentity("Glacial Fortress", ""));
cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Glorious Anthem", ""));
cubeCards.add(new DraftCube.CardIdentity("Glorybringer", ""));
cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster", ""));
cubeCards.add(new DraftCube.CardIdentity("God-Pharaoh's Gift", ""));
cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", ""));
cubeCards.add(new DraftCube.CardIdentity("Gonti, Lord of Luxury", ""));
cubeCards.add(new DraftCube.CardIdentity("Grave Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Gray Merchant of Asphodel", ""));
cubeCards.add(new DraftCube.CardIdentity("Greater Gargadon", ""));
cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", ""));
cubeCards.add(new DraftCube.CardIdentity("Greenwarden of Murasa", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Griselbrand", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Spiritkeeper", ""));
cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", ""));
cubeCards.add(new DraftCube.CardIdentity("Harbinger of the Tides", ""));
cubeCards.add(new DraftCube.CardIdentity("Harmonize", ""));
cubeCards.add(new DraftCube.CardIdentity("Hazoret the Fervent", ""));
cubeCards.add(new DraftCube.CardIdentity("Hellrider", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", ""));
cubeCards.add(new DraftCube.CardIdentity("Hidden Dragonslayer", ""));
cubeCards.add(new DraftCube.CardIdentity("Hinterland Harbor", ""));
cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", ""));
cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", ""));
cubeCards.add(new DraftCube.CardIdentity("Hordeling Outburst", ""));
cubeCards.add(new DraftCube.CardIdentity("Hornet Queen", ""));
cubeCards.add(new DraftCube.CardIdentity("Hostage Taker", ""));
cubeCards.add(new DraftCube.CardIdentity("Hour of Devastation", ""));
cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", ""));
cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", ""));
cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter", ""));
cubeCards.add(new DraftCube.CardIdentity("Icefall Regent", ""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter", ""));
cubeCards.add(new DraftCube.CardIdentity("Impulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Incendiary Flow", ""));
cubeCards.add(new DraftCube.CardIdentity("Incinerate", ""));
cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", ""));
cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new DraftCube.CardIdentity("Into the Roil", ""));
cubeCards.add(new DraftCube.CardIdentity("Ire Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Isamaru, Hound of Konda", ""));
cubeCards.add(new DraftCube.CardIdentity("Isolated Chapel", ""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", ""));
cubeCards.add(new DraftCube.CardIdentity("Jackal Pup", ""));
cubeCards.add(new DraftCube.CardIdentity("Jadelight Ranger", ""));
cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Journey to Nowhere", ""));
cubeCards.add(new DraftCube.CardIdentity("Kalitas, Traitor of Ghet", ""));
cubeCards.add(new DraftCube.CardIdentity("Karmic Guide", ""));
cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", ""));
cubeCards.add(new DraftCube.CardIdentity("Keiga, the Tide Star", ""));
cubeCards.add(new DraftCube.CardIdentity("Keranos, God of Storms", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiln Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiora's Follower", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiora, the Crashing Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Kira, Great Glass-Spinner", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", ""));
cubeCards.add(new DraftCube.CardIdentity("Knight of the Reliquary", ""));
cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach", ""));
cubeCards.add(new DraftCube.CardIdentity("Kokusho, the Evening Star", ""));
cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer", ""));
cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", ""));
cubeCards.add(new DraftCube.CardIdentity("Land Tax", ""));
cubeCards.add(new DraftCube.CardIdentity("Languish", ""));
cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", ""));
cubeCards.add(new DraftCube.CardIdentity("Legacy's Allure", ""));
cubeCards.add(new DraftCube.CardIdentity("Legion's Landing", ""));
cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Mauler", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana Vess", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, Death's Majesty", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, Heretical Healer", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, the Last Hope", ""));
cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", ""));
cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence", ""));
cubeCards.add(new DraftCube.CardIdentity("Linvala, the Preserver", ""));
cubeCards.add(new DraftCube.CardIdentity("Living Death", ""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", ""));
cubeCards.add(new DraftCube.CardIdentity("Loxodon Warhammer", ""));
cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", ""));
cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Magma Jet", ""));
cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin", ""));
cubeCards.add(new DraftCube.CardIdentity("Malicious Affliction", ""));
cubeCards.add(new DraftCube.CardIdentity("Man-o'-War", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", ""));
cubeCards.add(new DraftCube.CardIdentity("Managorger Hydra", ""));
cubeCards.add(new DraftCube.CardIdentity("Manic Vandal", ""));
cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", ""));
cubeCards.add(new DraftCube.CardIdentity("Martial Coup", ""));
cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm", ""));
cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", ""));
cubeCards.add(new DraftCube.CardIdentity("Master of Waves", ""));
cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", ""));
cubeCards.add(new DraftCube.CardIdentity("Mentor of the Meek", ""));
cubeCards.add(new DraftCube.CardIdentity("Merfolk Looter", ""));
cubeCards.add(new DraftCube.CardIdentity("Mimic Vat", ""));
cubeCards.add(new DraftCube.CardIdentity("Mind Stone", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirror Entity", ""));
cubeCards.add(new DraftCube.CardIdentity("Miscalculation", ""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", ""));
cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", ""));
cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars", ""));
cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", ""));
cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", ""));
cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", ""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Cut", ""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Redcap", ""));
cubeCards.add(new DraftCube.CardIdentity("Mutavault", ""));
cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", ""));
cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", ""));
cubeCards.add(new DraftCube.CardIdentity("Natural Order", ""));
cubeCards.add(new DraftCube.CardIdentity("Nature's Lore", ""));
cubeCards.add(new DraftCube.CardIdentity("Necromancy", ""));
cubeCards.add(new DraftCube.CardIdentity("Needle Spires", ""));
cubeCards.add(new DraftCube.CardIdentity("Negate", ""));
cubeCards.add(new DraftCube.CardIdentity("Nekrataal", ""));
cubeCards.add(new DraftCube.CardIdentity("Nevinyrral's Disk", ""));
cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, God-Pharaoh", ""));
cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker", ""));
cubeCards.add(new DraftCube.CardIdentity("Nightveil Specter", ""));
cubeCards.add(new DraftCube.CardIdentity("Nimble Obstructionist", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Vastwood Seer", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Vital Force", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Voice of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Noxious Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx", ""));
cubeCards.add(new DraftCube.CardIdentity("Oath of Nissa", ""));
cubeCards.add(new DraftCube.CardIdentity("Ob Nixilis Reignited", ""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", ""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Stone", ""));
cubeCards.add(new DraftCube.CardIdentity("Obstinate Baloth", ""));
cubeCards.add(new DraftCube.CardIdentity("Old Man of the Sea", ""));
cubeCards.add(new DraftCube.CardIdentity("Olivia Voldaren", ""));
cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler", ""));
cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Opposition", ""));
cubeCards.add(new DraftCube.CardIdentity("Opt", ""));
cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", ""));
cubeCards.add(new DraftCube.CardIdentity("Oust", ""));
cubeCards.add(new DraftCube.CardIdentity("Outpost Siege", ""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Battlement", ""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Pack Rat", ""));
cubeCards.add(new DraftCube.CardIdentity("Pact of Negation", ""));
cubeCards.add(new DraftCube.CardIdentity("Parallax Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Part the Waterveil", ""));
cubeCards.add(new DraftCube.CardIdentity("Path to Exile", ""));
cubeCards.add(new DraftCube.CardIdentity("Pernicious Deed", ""));
cubeCards.add(new DraftCube.CardIdentity("Pestermite", ""));
cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Obliterator", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Rager", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", ""));
cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar", ""));
cubeCards.add(new DraftCube.CardIdentity("Pillar of Flame", ""));
cubeCards.add(new DraftCube.CardIdentity("Plateau", ""));
cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", ""));
cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", ""));
cubeCards.add(new DraftCube.CardIdentity("Ponder", ""));
cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", ""));
cubeCards.add(new DraftCube.CardIdentity("Precinct Captain", ""));
cubeCards.add(new DraftCube.CardIdentity("Preordain", ""));
cubeCards.add(new DraftCube.CardIdentity("Primal Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Profane Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Purphoros, God of the Forge", ""));
cubeCards.add(new DraftCube.CardIdentity("Pyroclasm", ""));
cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage", ""));
cubeCards.add(new DraftCube.CardIdentity("Quarantine Field", ""));
cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", ""));
cubeCards.add(new DraftCube.CardIdentity("Raise the Alarm", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", ""));
cubeCards.add(new DraftCube.CardIdentity("Ral Zarek", ""));
cubeCards.add(new DraftCube.CardIdentity("Rampaging Baloths", ""));
cubeCards.add(new DraftCube.CardIdentity("Rampaging Ferocidon", ""));
cubeCards.add(new DraftCube.CardIdentity("Rampant Growth", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravages of War", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravenous Chupacabra", ""));
cubeCards.add(new DraftCube.CardIdentity("Razaketh, the Foulblooded", ""));
cubeCards.add(new DraftCube.CardIdentity("Razorverge Thicket", ""));
cubeCards.add(new DraftCube.CardIdentity("Read the Bones", ""));
cubeCards.add(new DraftCube.CardIdentity("Reanimate", ""));
cubeCards.add(new DraftCube.CardIdentity("Reckless Bushwhacker", ""));
cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", ""));
cubeCards.add(new DraftCube.CardIdentity("Recruiter of the Guard", ""));
cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", ""));
cubeCards.add(new DraftCube.CardIdentity("Reflecting Pool", ""));
cubeCards.add(new DraftCube.CardIdentity("Reflector Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Regrowth", ""));
cubeCards.add(new DraftCube.CardIdentity("Rekindling Phoenix", ""));
cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus", ""));
cubeCards.add(new DraftCube.CardIdentity("Remand", ""));
cubeCards.add(new DraftCube.CardIdentity("Remove Soul", ""));
cubeCards.add(new DraftCube.CardIdentity("Repeal", ""));
cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Reveillark", ""));
cubeCards.add(new DraftCube.CardIdentity("Rift Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", ""));
cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", ""));
cubeCards.add(new DraftCube.CardIdentity("Rishkar, Peema Renegade", ""));
cubeCards.add(new DraftCube.CardIdentity("Roast", ""));
cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", ""));
cubeCards.add(new DraftCube.CardIdentity("Rootbound Crag", ""));
cubeCards.add(new DraftCube.CardIdentity("Rune-Scarred Demon", ""));
cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", ""));
cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Sarkhan, the Dragonspeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Savannah", ""));
cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", ""));
cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", ""));
cubeCards.add(new DraftCube.CardIdentity("Scrapheap Scrounger", ""));
cubeCards.add(new DraftCube.CardIdentity("Scrubland", ""));
cubeCards.add(new DraftCube.CardIdentity("Sea Gate Oracle", ""));
cubeCards.add(new DraftCube.CardIdentity("Seachrome Coast", ""));
cubeCards.add(new DraftCube.CardIdentity("Seal of Fire", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Azcanta", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow", ""));
cubeCards.add(new DraftCube.CardIdentity("Searing Spear", ""));
cubeCards.add(new DraftCube.CardIdentity("Secure the Wastes", ""));
cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way", ""));
cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", ""));
cubeCards.add(new DraftCube.CardIdentity("Selvala, Heart of the Wilds", ""));
cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", ""));
cubeCards.add(new DraftCube.CardIdentity("Serendib Efreet", ""));
cubeCards.add(new DraftCube.CardIdentity("Serum Visions", ""));
cubeCards.add(new DraftCube.CardIdentity("Settle the Wreckage", ""));
cubeCards.add(new DraftCube.CardIdentity("Shaman of Forgotten Ways", ""));
cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", ""));
cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", ""));
cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", ""));
cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One", ""));
cubeCards.add(new DraftCube.CardIdentity("Show and Tell", ""));
cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", ""));
cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", ""));
cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin", ""));
cubeCards.add(new DraftCube.CardIdentity("Skinrender", ""));
cubeCards.add(new DraftCube.CardIdentity("Skymarcher Aspirant", ""));
cubeCards.add(new DraftCube.CardIdentity("Slagstorm", ""));
cubeCards.add(new DraftCube.CardIdentity("Slaughter Pact", ""));
cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", ""));
cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", ""));
cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", ""));
cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads", ""));
cubeCards.add(new DraftCube.CardIdentity("Sorin Markov", ""));
cubeCards.add(new DraftCube.CardIdentity("Sorin, Solemn Visitor", ""));
cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", ""));
cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", ""));
cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", ""));
cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", ""));
cubeCards.add(new DraftCube.CardIdentity("Spell Queller", ""));
cubeCards.add(new DraftCube.CardIdentity("Spellskite", ""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", ""));
cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", ""));
cubeCards.add(new DraftCube.CardIdentity("Staggershock", ""));
cubeCards.add(new DraftCube.CardIdentity("Steam Vents", ""));
cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", ""));
cubeCards.add(new DraftCube.CardIdentity("Stoke the Flames", ""));
cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", ""));
cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Stormchaser Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Stroke of Genius", ""));
cubeCards.add(new DraftCube.CardIdentity("Stromkirk Noble", ""));
cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", ""));
cubeCards.add(new DraftCube.CardIdentity("Sublime Archangel", ""));
cubeCards.add(new DraftCube.CardIdentity("Sulfur Falls", ""));
cubeCards.add(new DraftCube.CardIdentity("Sun Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Sunpetal Grove", ""));
cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict", ""));
cubeCards.add(new DraftCube.CardIdentity("Surrak, the Hunt Caller", ""));
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("Swords to Plowshares", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Advocate", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", ""));
cubeCards.add(new DraftCube.CardIdentity("Taiga", ""));
cubeCards.add(new DraftCube.CardIdentity("Talrand, Sky Summoner", ""));
cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage", ""));
cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", ""));
cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf", ""));
cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", ""));
cubeCards.add(new DraftCube.CardIdentity("Teferi, Mage of Zhalfir", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple Garden", ""));
cubeCards.add(new DraftCube.CardIdentity("Terastodon", ""));
cubeCards.add(new DraftCube.CardIdentity("Terminate", ""));
cubeCards.add(new DraftCube.CardIdentity("Terminus", ""));
cubeCards.add(new DraftCube.CardIdentity("Tetzimoc, Primal Death", ""));
cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", ""));
cubeCards.add(new DraftCube.CardIdentity("Thalia, Heretic Cathar", ""));
cubeCards.add(new DraftCube.CardIdentity("Thassa, God of the Sea", ""));
cubeCards.add(new DraftCube.CardIdentity("The Scarab God", ""));
cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", ""));
cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", ""));
cubeCards.add(new DraftCube.CardIdentity("Thragtusk", ""));
cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", ""));
cubeCards.add(new DraftCube.CardIdentity("Thunderbreak Regent", ""));
cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", ""));
cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Warp", ""));
cubeCards.add(new DraftCube.CardIdentity("Tireless Tracker", ""));
cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", ""));
cubeCards.add(new DraftCube.CardIdentity("Torch Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Tower of the Magistrate", ""));
cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", ""));
cubeCards.add(new DraftCube.CardIdentity("Treachery", ""));
cubeCards.add(new DraftCube.CardIdentity("Tropical Island", ""));
cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", ""));
cubeCards.add(new DraftCube.CardIdentity("Tundra", ""));
cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", ""));
cubeCards.add(new DraftCube.CardIdentity("Ultimate Price", ""));
cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", ""));
cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", ""));
cubeCards.add(new DraftCube.CardIdentity("Underground Sea", ""));
cubeCards.add(new DraftCube.CardIdentity("Underworld Connections", ""));
cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", ""));
cubeCards.add(new DraftCube.CardIdentity("Upheaval", ""));
cubeCards.add(new DraftCube.CardIdentity("Utopia Sprawl", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Hexmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", ""));
cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", ""));
cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", ""));
cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new DraftCube.CardIdentity("Verdurous Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Vindicate", ""));
cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", ""));
cubeCards.add(new DraftCube.CardIdentity("Volrath's Stronghold", ""));
cubeCards.add(new DraftCube.CardIdentity("Vraska's Contempt", ""));
cubeCards.add(new DraftCube.CardIdentity("Vraska, Relic Seeker", ""));
cubeCards.add(new DraftCube.CardIdentity("Walking Ballista", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", ""));
cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", ""));
cubeCards.add(new DraftCube.CardIdentity("Wasteland", ""));
cubeCards.add(new DraftCube.CardIdentity("Watery Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Whip of Erebos", ""));
cubeCards.add(new DraftCube.CardIdentity("Whirler Rogue", ""));
cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental", ""));
cubeCards.add(new DraftCube.CardIdentity("Wickerbough Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Windbrisk Heights", ""));
cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", ""));
cubeCards.add(new DraftCube.CardIdentity("Wolfir Silverheart", ""));
cubeCards.add(new DraftCube.CardIdentity("Wood Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", ""));
cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", ""));
cubeCards.add(new DraftCube.CardIdentity("Woodland Cemetery", ""));
cubeCards.add(new DraftCube.CardIdentity("Wrath of God", ""));
cubeCards.add(new DraftCube.CardIdentity("Wretched Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", ""));
cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler", ""));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", ""));
}
}

View file

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

View file

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

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<artifactId>mage-server-plugins</artifactId>

View file

@ -110,12 +110,13 @@
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube September 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legacy Cube January 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
<draftCube name="MTGO Legacy Cube April 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube 2015 September" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube 2016 January" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube 2016 September" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legacy Cube 2017 January" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
<draftCube name="MTGO Legacy Cube 2017 April" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
<draftCube name="MTGO Legacy Cube 2018 February" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube2018February"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ModernCube2017"/>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<artifactId>mage-server</artifactId>
@ -76,6 +76,12 @@
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.16.1</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -107,12 +107,13 @@
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube March 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube September 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube January 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube September 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legacy Cube January 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
<draftCube name="MTGO Legacy Cube April 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
<draftCube name="MTGO Legacy Cube 2015 September" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
<draftCube name="MTGO Legacy Cube 2016 January" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
<draftCube name="MTGO Legacy Cube 2016 September" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
<draftCube name="MTGO Legacy Cube 2017 January" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
<draftCube name="MTGO Legacy Cube 2017 April" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
<draftCube name="MTGO Legacy Cube 2018 February" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube2018February"/>
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ModernCube2017"/>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.27</version>
<version>1.4.28</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -63,7 +63,7 @@ public class AnimationModule extends CardImpl {
public AnimationModule(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
// Whenever one or more +1/+1 counters are placed on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.
// Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.
this.addAbility(new AnimationModuleTriggeredAbility());
// {3}, {T}: Choose a counter on target permanent or player. Give that permanent or player another counter of that kind.
@ -117,7 +117,7 @@ class AnimationModuleTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever one or more +1/+1 counters are placed on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.";
return "Whenever one or more +1/+1 counters are put on a permanent you control, you may pay {1}. If you do, create a 1/1 colorless Servo artifact creature token.";
}
}

View file

@ -29,7 +29,7 @@ package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
@ -37,7 +37,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.events.GameEvent;
import mage.constants.TargetController;
/**
*
@ -46,7 +46,7 @@ import mage.game.events.GameEvent;
public class ArchwingDragon extends CardImpl {
public ArchwingDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}");
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(4);
@ -54,8 +54,10 @@ public class ArchwingDragon extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
this.addAbility(HasteAbility.getInstance());
// At the beginning of the end step, return Archwing Dragon to its owner's hand.
this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", new ReturnToHandSourceEffect(true), false));
this.addAbility(new BeginningOfEndStepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.ANY, false));
}
public ArchwingDragon(final ArchwingDragon card) {

View file

@ -69,7 +69,7 @@ public class BloodcrazedHoplite extends CardImpl {
// Heroic - Whenever you cast a spell that targets Bloodcrazed Hoplite, put a +1/+1 counter on it.
this.addAbility(new HeroicAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), false)));
// Whenever a +1/+1 counter is placed on Bloodcrazed Hoplite, remove a +1/+1 counter from target creature an opponent controls.
// Whenever a +1/+1 counter is put on Bloodcrazed Hoplite, remove a +1/+1 counter from target creature an opponent controls.
Ability ability = new BloodcrazedHopliteTriggeredAbility();
ability.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(ability);
@ -112,6 +112,6 @@ class BloodcrazedHopliteTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a +1/+1 counter is placed on {this}, " + super.getRule();
return "Whenever a +1/+1 counter is put on {this}, " + super.getRule();
}
}

View file

@ -43,6 +43,7 @@ import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@ -56,6 +57,7 @@ public class BrothersYamazaki extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(new AnotherPredicate());
filter.add(new NamePredicate("Brothers Yamazaki"));
}

View file

@ -0,0 +1,121 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.b;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetArtifactPermanent;
/**
*
* @author sinsedrix
*/
public class BuildersBane extends CardImpl {
public BuildersBane(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{R}");
// Destroy X target artifacts. Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way.
this.getSpellAbility().addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addEffect(new BuildersBaneEffect());
}
@Override
public void adjustTargets(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
ability.getTargets().clear();
int xValue = ability.getManaCostsToPay().getX();
ability.addTarget(new TargetArtifactPermanent(xValue, xValue));
}
}
public BuildersBane(final BuildersBane card) {
super(card);
}
@Override
public BuildersBane copy() {
return new BuildersBane(this);
}
}
class BuildersBaneEffect extends OneShotEffect {
public BuildersBaneEffect() {
super(Outcome.DestroyPermanent);
this.staticText = "Destroy X target artifacts. {this} deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way";
}
public BuildersBaneEffect(final BuildersBaneEffect effect) {
super(effect);
}
@Override
public BuildersBaneEffect copy() {
return new BuildersBaneEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Map<UUID, Integer> destroyedArtifactPerPlayer = new HashMap<>();
// Destroy X target artifacts.
for (UUID targetID : this.targetPointer.getTargets(game, source)) {
Permanent permanent = game.getPermanent(targetID);
if (permanent != null) {
if (permanent.destroy(source.getSourceId(), game, false)) {
if (game.getState().getZone(permanent.getId()) == Zone.GRAVEYARD) {
destroyedArtifactPerPlayer.merge(permanent.getControllerId(), 1, Integer::sum);
}
}
}
}
// Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way.
for (Map.Entry<UUID, Integer> entry : destroyedArtifactPerPlayer.entrySet()) {
Player player = game.getPlayer(entry.getKey());
if(player != null) {
player.damage(entry.getValue(), source.getSourceId(), game, false, true);
}
}
return true;
}
}

View file

@ -65,7 +65,7 @@ public class CorpsejackMenace extends CardImpl {
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead.
// If one or more +1/+1 counters would be put on a creature you control, twice that many +1/+1 counters are put on it instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CorpsejackMenaceReplacementEffect()));
}
@ -84,7 +84,7 @@ class CorpsejackMenaceReplacementEffect extends ReplacementEffectImpl {
CorpsejackMenaceReplacementEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
staticText = "If one or more +1/+1 counters would be placed on a creature you control, twice that many +1/+1 counters are placed on it instead";
staticText = "If one or more +1/+1 counters would be put on a creature you control, twice that many +1/+1 counters are put on it instead";
}
CorpsejackMenaceReplacementEffect(final CorpsejackMenaceReplacementEffect effect) {

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class Crevasse extends CardImpl {
public Crevasse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
// Creatures with mountainwalk can be blocked as though they didn't have mountainwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CrevasseEffect()));
}
public Crevasse(final Crevasse card) {
super(card);
}
@Override
public Crevasse copy() {
return new Crevasse(this);
}
}
class CrevasseEffect extends AsThoughEffectImpl {
public CrevasseEffect() {
super(AsThoughEffectType.BLOCK_MOUNTAINWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with mountainwalk can be blocked as though they didn't have mountainwalk";
}
public CrevasseEffect(final CrevasseEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public CrevasseEffect copy() {
return new CrevasseEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -27,18 +27,22 @@
*/
package mage.cards.c;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityType;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.CurseOfTheSwineBoarToken;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
/**
@ -58,7 +62,7 @@ public class CurseOfTheSwine extends CardImpl {
@Override
public void adjustTargets(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
if (ability instanceof SpellAbility && ability.getAbilityType().equals(AbilityType.SPELL)) {
ability.getTargets().clear();
ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX()));
}
@ -92,15 +96,24 @@ class CurseOfTheSwineEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
Permanent creature = game.getPermanent(targetId);
if (creature != null) {
if (creature.moveToExile(null, null, source.getSourceId(), game) || creature.moveToZone(Zone.COMMAND, source.getSourceId(), game, false)) {
CurseOfTheSwineBoarToken swineToken = new CurseOfTheSwineBoarToken();
swineToken.putOntoBattlefield(1, game, source.getSourceId(), creature.getControllerId());
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Map<UUID, Integer> playersWithTargets = new HashMap<>();
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
Permanent creature = game.getPermanent(targetId);
if (creature != null) {
if (controller.moveCards(creature, Zone.EXILED, source, game)) {
playersWithTargets.put(creature.getControllerId(), playersWithTargets.getOrDefault(creature.getControllerId(), 0) + 1);
}
}
}
CurseOfTheSwineBoarToken swineToken = new CurseOfTheSwineBoarToken();
for (UUID playerId : playersWithTargets.keySet()) {
swineToken.putOntoBattlefield(playersWithTargets.get(playerId), game, source.getSourceId(), playerId);
}
return true;
}
return true;
return false;
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.d;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class Deadfall extends CardImpl {
public Deadfall(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
// Creatures with forestwalk can be blocked as though they didn't have forestwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DeadfallEffect()));
}
public Deadfall(final Deadfall card) {
super(card);
}
@Override
public Deadfall copy() {
return new Deadfall(this);
}
}
class DeadfallEffect extends AsThoughEffectImpl {
public DeadfallEffect() {
super(AsThoughEffectType.BLOCK_FORESTWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with forestwalk can be blocked as though they didn't have forestwalk";
}
public DeadfallEffect(final DeadfallEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public DeadfallEffect copy() {
return new DeadfallEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -35,7 +35,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
@ -53,7 +52,7 @@ public class DinosaurHunter extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Whenever Dinosaur Hunter deals combat damage to a Dinosaur, destroy that creature.
// Whenever Dinosaur Hunter deals damage to a Dinosaur, destroy that creature.
this.addAbility(new DinosaurHunterAbility());
}
@ -89,11 +88,10 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((DamageEvent) event).isCombatDamage()
&& event.getSourceId().equals(getSourceId())) {
if (event.getSourceId().equals(getSourceId())) {
Permanent targetPermanet = game.getPermanentOrLKIBattlefield(event.getTargetId());
if (targetPermanet.hasSubtype(SubType.DINOSAUR, game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(targetPermanet, game));
getEffects().setTargetPointer(new FixedTarget(targetPermanet, game));
return true;
}
}
@ -102,6 +100,6 @@ class DinosaurHunterAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever {this} deals combat damage to a Dinosaur, destroy that creature.";
return "Whenever {this} deals damage to a Dinosaur, destroy that creature.";
}
}

View file

@ -54,7 +54,7 @@ public class DoublingSeason extends CardImpl {
// If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreateTwiceThatManyTokensEffect()));
// If an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead.
// If an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DoublingSeasonCounterEffect()));
}
@ -75,7 +75,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl {
DoublingSeasonCounterEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
staticText = "If an effect would place one or more counters on a permanent you control, it places twice that many of those counters on that permanent instead";
staticText = "If an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead";
}
DoublingSeasonCounterEffect(final DoublingSeasonCounterEffect effect) {

View file

@ -31,7 +31,6 @@ import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect;
import mage.abilities.keyword.FearAbility;
@ -105,11 +104,7 @@ class DreadTriggeredAbility extends TriggeredAbilityImpl {
if (event.getPlayerId().equals(this.getControllerId())) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null && permanent.isCreature()) {
for (Effect effect : this.getEffects()) {
if (effect instanceof DestroyTargetEffect) {
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
}
}
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
return true;
}
}

View file

@ -57,7 +57,7 @@ public class EnduringScalelord extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever one or more +1/+1 counters are place on another creature you control, you may put a +1/+1 counter on Enduring Scaleguard.
// Whenever one or more +1/+1 counters are put on another creature you control, you may put a +1/+1 counter on Enduring Scaleguard.
this.addAbility(new EnduringScalelordTriggeredAbility());
}
@ -109,6 +109,6 @@ class EnduringScalelordTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever one or more +1/+1 counters are place on another creature you control, you may put a +1/+1 counter on {this}.";
return "Whenever one or more +1/+1 counters are put on another creature you control, you may put a +1/+1 counter on {this}.";
}
}

View file

@ -94,6 +94,7 @@ class ExhumeEffect extends OneShotEffect {
FilterCreatureCard filterCreatureCard = new FilterCreatureCard("creature card from your graveyard");
filterCreatureCard.add(new OwnerIdPredicate(playerId));
TargetCardInGraveyard target = new TargetCardInGraveyard(filterCreatureCard);
target.setNotTarget(true);
if (target.canChoose(playerId, game)
&& player.chooseTarget(outcome, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());

View file

@ -59,11 +59,11 @@ public class FairgroundsTrumpeter extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// At the beginning of each end step, if a +1/+1 counter was placed on a permanent under your control this turn, put a +1/+1 counter on Fairgrounds Trumpeter.
// At the beginning of each end step, if a +1/+1 counter was put on a permanent under your control this turn, put a +1/+1 counter on Fairgrounds Trumpeter.
this.addAbility(new ConditionalTriggeredAbility(new BeginningOfEndStepTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
TargetController.ANY, false), FairgroundsTrumpeterCondition.instance,
"At the beginning of each end step, if a +1/+1 counter was placed on a permanent under your control this turn, put a +1/+1 counter on {this}."),
"At the beginning of each end step, if a +1/+1 counter was put on a permanent under your control this turn, put a +1/+1 counter on {this}."),
new FairgroundsTrumpeterWatcher());
}
@ -89,7 +89,7 @@ enum FairgroundsTrumpeterCondition implements Condition {
@Override
public String toString() {
return "if a +1/+1 counter was placed on a permanent under your control this turn";
return "if a +1/+1 counter was put on a permanent under your control this turn";
}
}

View file

@ -61,7 +61,7 @@ public class FathomMage extends CardImpl {
// has greater power or toughness than this creature, put a +1/+1 counter on this creature.)
this.addAbility(new EvolveAbility());
//Whenever a +1/+1 counter is placed on Fathom Mage, you may draw a card.
//Whenever a +1/+1 counter is put on Fathom Mage, you may draw a card.
this.addAbility(new FathomMageTriggeredAbility());
}
@ -102,6 +102,6 @@ class FathomMageTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a +1/+1 counter is placed on {this}, " + super.getRule();
return "Whenever a +1/+1 counter is put on {this}, " + super.getRule();
}
}

View file

@ -50,7 +50,7 @@ public class FlourishingDefenses extends CardImpl {
public FlourishingDefenses(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}");
// Whenever a -1/-1 counter is placed on a creature, you may create a 1/1 green Elf Warrior creature token.
// Whenever a -1/-1 counter is put on a creature, you may create a 1/1 green Elf Warrior creature token.
this.addAbility(new FlourishingDefensesTriggeredAbility());
}
@ -98,6 +98,6 @@ class FlourishingDefensesTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "Whenever a -1/-1 counter is placed on a creature, you may create a 1/1 green Elf Warrior creature token.";
return "Whenever a -1/-1 counter is put on a creature, you may create a 1/1 green Elf Warrior creature token.";
}
}

View file

@ -30,12 +30,13 @@ package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@ -48,6 +49,7 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/**
*
@ -62,7 +64,7 @@ public class GiltLeafArchdruid extends CardImpl {
}
public GiltLeafArchdruid(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}");
this.subtype.add(SubType.ELF);
this.subtype.add(SubType.DRUID);
@ -73,7 +75,7 @@ public class GiltLeafArchdruid extends CardImpl {
this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), filterSpell, true));
// Tap seven untapped Druids you control: Gain control of all lands target player controls.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainControlAllLandsEffect(Duration.EndOfGame), new TapTargetCost(new TargetControlledCreaturePermanent(7, 7, new FilterControlledCreaturePermanent(SubType.DRUID, "Druids you control"), true)));
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GiltLeafArchdruidEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(7, 7, new FilterControlledCreaturePermanent(SubType.DRUID, "Druids you control"), true)));
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
@ -88,38 +90,36 @@ public class GiltLeafArchdruid extends CardImpl {
}
}
class GainControlAllLandsEffect extends ContinuousEffectImpl {
class GiltLeafArchdruidEffect extends OneShotEffect {
public GainControlAllLandsEffect(Duration duration) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
public GiltLeafArchdruidEffect() {
super(Outcome.GainControl);
this.staticText = "gain control of all lands target player controls";
}
public GainControlAllLandsEffect(final GainControlAllLandsEffect effect) {
public GiltLeafArchdruidEffect(final GiltLeafArchdruidEffect effect) {
super(effect);
}
@Override
public GainControlAllLandsEffect copy() {
return new GainControlAllLandsEffect(this);
public GiltLeafArchdruidEffect copy() {
return new GiltLeafArchdruidEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source));
if (targetPlayer != null && targetPlayer.isInGame()) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LANDS, targetPointer.getFirst(game, source), game)) {
if (controller != null && targetPlayer != null) {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_LANDS, targetPlayer.getId(), game)) {
if (permanent != null) {
permanent.changeControllerId(source.getControllerId(), game);
ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true);
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
}
}
} else {
discard();
return true;
}
return true;
}
@Override
public String getText(Mode mode) {
return "Gain control of all lands target player controls";
return false;
}
}

View file

@ -0,0 +1,99 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.g;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public class GostaDirk extends CardImpl {
public GostaDirk(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}{U}{U}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WARRIOR);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// First strike
this.addAbility(FirstStrikeAbility.getInstance());
// Creatures with islandwalk can be blocked as though they didn't have islandwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GostaDirkEffect()));
}
public GostaDirk(final GostaDirk card) {
super(card);
}
@Override
public GostaDirk copy() {
return new GostaDirk(this);
}
}
class GostaDirkEffect extends AsThoughEffectImpl {
public GostaDirkEffect() {
super(AsThoughEffectType.BLOCK_ISLANDWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with islandwalk can be blocked as though they didn't have islandwalk";
}
public GostaDirkEffect(final GostaDirkEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public GostaDirkEffect copy() {
return new GostaDirkEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class GreatWall extends CardImpl {
public GreatWall(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// Creatures with plainswalk can be blocked as though they didn't have plainswalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GreatWallEffect()));
}
public GreatWall(final GreatWall card) {
super(card);
}
@Override
public GreatWall copy() {
return new GreatWall(this);
}
}
class GreatWallEffect extends AsThoughEffectImpl {
public GreatWallEffect() {
super(AsThoughEffectType.BLOCK_PLAINSWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with plainswalk can be blocked as though they didn't have plainswalk";
}
public GreatWallEffect(final GreatWallEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public GreatWallEffect copy() {
return new GreatWallEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -52,7 +52,7 @@ public class HardenedScales extends CardImpl {
public HardenedScales(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}");
// If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead.
// If one or more +1/+1 counters would be put on a creature you control, that many plus one +1/+1 counters are put on it instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HardenedScalesEffect()));
}
@ -71,7 +71,7 @@ class HardenedScalesEffect extends ReplacementEffectImpl {
HardenedScalesEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
staticText = "If one or more +1/+1 counters would be placed on a creature you control, that many plus one +1/+1 counters are placed on it instead";
staticText = "If one or more +1/+1 counters would be put on a creature you control, that many plus one +1/+1 counters are put on it instead";
}
HardenedScalesEffect(final HardenedScalesEffect effect) {

View file

@ -29,10 +29,9 @@ package mage.cards.h;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.cards.CardImpl;
@ -52,7 +51,7 @@ import mage.target.targetpointer.FixedTarget;
public class HeatShimmer extends CardImpl {
public HeatShimmer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}");
// Create a token that's a copy of target creature. That token has haste and "At the beginning of the end step, exile this permanent."
this.getSpellAbility().addEffect(new HeatShimmerEffect());
@ -89,15 +88,15 @@ class HeatShimmerEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source));
if (controller != null && permanent != null) {
if (controller != null
&& permanent != null) {
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true);
effect.setTargetPointer(new FixedTarget(permanent, game));
effect.apply(game, source);
for (Permanent addedToken : effect.getAddedPermanent()) {
Effect exileEffect = new ExileTargetEffect();
exileEffect.setTargetPointer(new FixedTarget(addedToken, game));
new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfTurnStepPostDelayedTriggeredAbility(exileEffect), false).apply(game, source);
}
ExileTargetEffect exileEffect = new ExileTargetEffect();
exileEffect.setTargetPointer(new FixedTarget(effect.getAddedPermanent().get(0), game));
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect);
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;

View file

@ -104,10 +104,7 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl {
Permanent equipment = game.getPermanent(this.getSourceId());
if (equipment != null && equipment.getAttachedTo() != null) {
if (Objects.equals(event.getTargetId(), equipment.getAttachedTo())) {
for(Effect effect : this.getEffects())
{
effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo()));
}
this.getEffects().setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game));
return true;
}
}
@ -118,4 +115,4 @@ class HotSoupTriggeredAbility extends TriggeredAbilityImpl {
public String getRule() {
return "Whenever equipped creature is dealt damage, " + super.getRule();
}
}
}

View file

@ -49,9 +49,9 @@ import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
@ -69,7 +69,7 @@ import mage.target.targetpointer.FixedTarget;
public class KheruLichLord extends CardImpl {
public KheruLichLord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{G}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}{U}");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.WIZARD);
@ -166,14 +166,8 @@ class KheruLichLordReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, game.getState().getZone(card.getId()), true);
}
}
return true;
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
return false;
}
@Override

View file

@ -0,0 +1,129 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.l;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author L_J
*/
public class LordMagnus extends CardImpl {
public LordMagnus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{W}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.DRUID);
this.power = new MageInt(4);
this.toughness = new MageInt(3);
// First strike
this.addAbility(FirstStrikeAbility.getInstance());
// Creatures with plainswalk can be blocked as though they didn't have plainswalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LordMagnusFirstEffect()));
// Creatures with forestwalk can be blocked as though they didn't have forestwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LordMagnusSecondEffect()));
}
public LordMagnus(final LordMagnus card) {
super(card);
}
@Override
public LordMagnus copy() {
return new LordMagnus(this);
}
}
class LordMagnusFirstEffect extends AsThoughEffectImpl {
public LordMagnusFirstEffect() {
super(AsThoughEffectType.BLOCK_PLAINSWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with plainswalk can be blocked as though they didn't have plainswalk";
}
public LordMagnusFirstEffect(final LordMagnusFirstEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public LordMagnusFirstEffect copy() {
return new LordMagnusFirstEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}
class LordMagnusSecondEffect extends AsThoughEffectImpl {
public LordMagnusSecondEffect() {
super(AsThoughEffectType.BLOCK_FORESTWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with forestwalk can be blocked as though they didn't have forestwalk";
}
public LordMagnusSecondEffect(final LordMagnusSecondEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public LordMagnusSecondEffect copy() {
return new LordMagnusSecondEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -63,7 +63,7 @@ public class MeliraSylvokOutcast extends CardImpl {
// You can't get poison counters.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MeliraSylvokOutcastEffect()));
// Creatures you control can't have -1/-1 counters placed on them.
// Creatures you control can't have -1/-1 counters put on them.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MeliraSylvokOutcastEffect2()));
// Creatures your opponents control lose infect.
@ -118,7 +118,7 @@ class MeliraSylvokOutcastEffect2 extends ReplacementEffectImpl {
public MeliraSylvokOutcastEffect2() {
super(Duration.WhileOnBattlefield, Outcome.PreventDamage);
staticText = "Creatures you control can't have -1/-1 counters placed on them";
staticText = "Creatures you control can't have -1/-1 counters put on them";
}
public MeliraSylvokOutcastEffect2(final MeliraSylvokOutcastEffect2 effect) {

View file

@ -51,7 +51,7 @@ public class MelirasKeepers extends CardImpl {
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Melira's Keepers can't have counters placed on it
// Melira's Keepers can't have counters put on it
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantHaveCountersSourceEffect()));
}

View file

@ -0,0 +1,99 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author jeffwadsworth
*/
public class MoralityShift extends CardImpl {
public MoralityShift(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{B}{B}");
// Exchange your graveyard and library. Then shuffle your library.
this.getSpellAbility().addEffect(new MoralityShiftEffect());
}
public MoralityShift(final MoralityShift card) {
super(card);
}
@Override
public MoralityShift copy() {
return new MoralityShift(this);
}
}
class MoralityShiftEffect extends OneShotEffect {
MoralityShiftEffect() {
super(Outcome.AIDontUseIt);
staticText = "Exchange your graveyard and library. Then shuffle your library.";
}
MoralityShiftEffect(MoralityShiftEffect effect) {
super(effect);
}
@Override
public MoralityShiftEffect copy() {
return new MoralityShiftEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Card> copyLibrary = controller.getLibrary().getCards(game);
Set<Card> copyGraveyard = controller.getGraveyard().getCards(game);
controller.getLibrary().clear();
controller.getGraveyard().clear();
controller.getGraveyard().addAll(copyLibrary);
controller.getLibrary().addAll(copyGraveyard, game);
controller.shuffleLibrary(source, game);
return true;
}
return false;
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.m;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.AddManaOfAnyColorEffect;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
/**
*
* @author spjspj/psjpsj
*/
public class MoxLotus extends CardImpl {
public MoxLotus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{15}");
// {t}: Add infinity (or 1*10^9 to account for a potential mana reflection) to your mana pool.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1000000000), new TapSourceCost()));
// {100}: Add one mana of any color to your mana pool.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(1), new ManaCostsImpl("{100}"));
this.addAbility(ability);
// You don't lose life due to mana burn.
// Situation normal??
}
public MoxLotus(final MoxLotus card) {
super(card);
}
@Override
public MoxLotus copy() {
return new MoxLotus(this);
}
}

View file

@ -29,7 +29,6 @@ package mage.cards.n;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -48,7 +47,7 @@ import mage.target.targetpointer.FixedTarget;
public class NoMercy extends CardImpl {
public NoMercy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
// Whenever a creature deals damage to you, destroy it.
this.addAbility(new NoMercyTriggeredAbility());
@ -88,9 +87,7 @@ public class NoMercy extends CardImpl {
if (event.getPlayerId().equals(this.getControllerId())) {
Permanent permanent = game.getPermanent(event.getSourceId());
if (permanent != null && permanent.isCreature()) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
}
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
return true;
}
}

View file

@ -107,11 +107,11 @@ class PandemoniumEffect extends OneShotEffect {
if (enteringCreature != null) {
Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget());
if (targetPermanent != null) {
targetPermanent.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true);
targetPermanent.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true);
} else {
Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget());
if (targetPlayer != null) {
targetPlayer.damage(enteringCreature.getPower().getValue(), source.getSourceId(), game, false, true);
targetPlayer.damage(enteringCreature.getPower().getValue(), enteringCreature.getId(), game, false, true);
}
}
return true;

View file

@ -52,7 +52,7 @@ public class PrimalVigor extends CardImpl {
// If one or more tokens would be created, twice that many of those tokens are created instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalVigorTokenEffect()));
// If one or more +1/+1 counters would be placed on a creature, twice that many +1/+1 counters are placed on that creature instead.
// If one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrimalVigorCounterEffect()));
}
@ -110,7 +110,7 @@ class PrimalVigorCounterEffect extends ReplacementEffectImpl {
PrimalVigorCounterEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false);
staticText = "If one or more +1/+1 counters would be placed on a creature, twice that many +1/+1 counters are placed on that creature instead";
staticText = "If one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead";
}
PrimalVigorCounterEffect(final PrimalVigorCounterEffect effect) {

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.q;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class Quagmire extends CardImpl {
public Quagmire(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
// Creatures with swampwalk can be blocked as though they didn't have swampwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new QuagmireEffect()));
}
public Quagmire(final Quagmire card) {
super(card);
}
@Override
public Quagmire copy() {
return new Quagmire(this);
}
}
class QuagmireEffect extends AsThoughEffectImpl {
public QuagmireEffect() {
super(AsThoughEffectType.BLOCK_SWAMPWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with swampwalk can be blocked as though they didn't have swampwalk";
}
public QuagmireEffect(final QuagmireEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public QuagmireEffect copy() {
return new QuagmireEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -25,34 +25,34 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.RemoveVariableCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
/**
* @author LevelX2
@ -60,12 +60,12 @@ import mage.target.common.TargetCreaturePermanent;
public class SkullmaneBaku extends CardImpl {
public SkullmaneBaku(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku.
this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.SPIRIT_OR_ARCANE_CARD, true));
@ -85,7 +85,7 @@ public class SkullmaneBaku extends CardImpl {
public SkullmaneBaku copy() {
return new SkullmaneBaku(this);
}
static class SkullmaneBakuUnboostEffect extends OneShotEffect {
public SkullmaneBakuUnboostEffect() {
@ -102,12 +102,14 @@ public class SkullmaneBaku extends CardImpl {
int numberToUnboost = 0;
for (Cost cost : source.getCosts()) {
if (cost instanceof RemoveVariableCountersSourceCost) {
numberToUnboost = ((RemoveVariableCountersSourceCost)cost).getAmount() * -1;
numberToUnboost = ((RemoveVariableCountersSourceCost) cost).getAmount() * -1;
}
}
Permanent creature = game.getPermanent(targetPointer.getFirst(game, source));
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (creature != null && numberToUnboost != 0) {
creature.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(numberToUnboost, numberToUnboost, Duration.EndOfTurn)), source.getSourceId(), game, false);
ContinuousEffect effect = new BoostTargetEffect(numberToUnboost, numberToUnboost, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(creature, game));
game.addEffect(effect, source);
}
return true;
}
@ -118,4 +120,4 @@ public class SkullmaneBaku extends CardImpl {
}
}
}
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class StaffOfTheAges extends CardImpl {
public StaffOfTheAges(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// Creatures with landwalk abilities can be blocked as though they didn't have those abilities.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new StaffOfTheAgesEffect()));
}
public StaffOfTheAges(final StaffOfTheAges card) {
super(card);
}
@Override
public StaffOfTheAges copy() {
return new StaffOfTheAges(this);
}
}
class StaffOfTheAgesEffect extends AsThoughEffectImpl {
public StaffOfTheAgesEffect() {
super(AsThoughEffectType.BLOCK_LANDWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with landwalk abilities can be blocked as though they didn't have those abilities";
}
public StaffOfTheAgesEffect(final StaffOfTheAgesEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public StaffOfTheAgesEffect copy() {
return new StaffOfTheAgesEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -53,7 +53,7 @@ public class Tatterkite extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Tatterkite can't have counters placed on it.
// Tatterkite can't have counters put on it.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantHaveCountersSourceEffect()));
}

View file

@ -0,0 +1,91 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.u;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
/**
*
* @author L_J
*/
public class Undertow extends CardImpl {
public Undertow(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
// Creatures with islandwalk can be blocked as though they didn't have islandwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UndertowEffect()));
}
public Undertow(final Undertow card) {
super(card);
}
@Override
public Undertow copy() {
return new Undertow(this);
}
}
class UndertowEffect extends AsThoughEffectImpl {
public UndertowEffect() {
super(AsThoughEffectType.BLOCK_ISLANDWALK, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Creatures with islandwalk can be blocked as though they didn't have islandwalk";
}
public UndertowEffect(final UndertowEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public UndertowEffect copy() {
return new UndertowEffect(this);
}
@Override
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
return true;
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.u;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.EntersTheBattlefieldEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
import mage.watchers.common.CreatureWasCastWatcher;
/**
*
* @author chrvanorle
*/
public class UphillBattle extends CardImpl {
public UphillBattle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
// Creatures played by your opponents enter the battlefield tapped.
Ability tapAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new UphillBattleTapEffect());
tapAbility.addWatcher(new CreatureWasCastWatcher());
tapAbility.addWatcher(new PlayCreatureLandWatcher());
addAbility(tapAbility);
}
public UphillBattle(final UphillBattle card) {
super(card);
}
@Override
public UphillBattle copy() {
return new UphillBattle(this);
}
}
class PlayCreatureLandWatcher extends Watcher {
final Set<UUID> playerPlayedLand = new HashSet<>(); // player that played land
final Set<UUID> landPlayed = new HashSet<>(); // land played
public PlayCreatureLandWatcher() {
super(PlayCreatureLandWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public PlayCreatureLandWatcher(final PlayCreatureLandWatcher watcher) {
super(watcher);
playerPlayedLand.addAll(watcher.playerPlayedLand);
landPlayed.addAll(watcher.landPlayed);
}
@Override
public PlayCreatureLandWatcher copy() {
return new PlayCreatureLandWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.PLAY_LAND) {
Card card = game.getCard(event.getTargetId());
if (card != null
&& card.isLand()
&& card.isCreature()
&& !playerPlayedLand.contains(event.getPlayerId())) {
playerPlayedLand.add(event.getPlayerId());
landPlayed.add(event.getTargetId());
}
}
}
@Override
public void reset() {
playerPlayedLand.clear();
landPlayed.clear();
super.reset();
}
public boolean landPlayed(UUID playerId) {
return playerPlayedLand.contains(playerId);
}
public boolean wasLandPlayed(UUID landId) {
return landPlayed.contains(landId);
}
}
class UphillBattleTapEffect extends ReplacementEffectImpl {
UphillBattleTapEffect() {
super(Duration.WhileOnBattlefield, Outcome.Tap);
staticText = "Creatures played by your opponents enter the battlefield tapped";
}
UphillBattleTapEffect(final UphillBattleTapEffect effect) {
super(effect);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent target = ((EntersTheBattlefieldEvent) event).getTarget();
CreatureWasCastWatcher creatureSpellWatcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName());
PlayCreatureLandWatcher landWatcher = (PlayCreatureLandWatcher) game.getState().getWatchers().get(PlayCreatureLandWatcher.class.getSimpleName());
if (target != null
&& ((creatureSpellWatcher != null && creatureSpellWatcher.wasCreatureCastThisTurn(target.getId()))
|| (landWatcher != null && landWatcher.wasLandPlayed(target.getId())))) {
target.setTapped(true);
}
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
if (permanent != null && permanent.isCreature()) {
return true;
}
}
return false;
}
@Override
public UphillBattleTapEffect copy() {
return new UphillBattleTapEffect(this);
}
}

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