diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java
index 7df4a984ff..9c5d93d6fe 100644
--- a/Mage.Client/src/main/java/mage/client/MageFrame.java
+++ b/Mage.Client/src/main/java/mage/client/MageFrame.java
@@ -239,10 +239,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
SessionHandler.startSession(this);
callbackClient = new CallbackClientImpl(this);
connectDialog = new ConnectDialog();
- desktopPane.add(connectDialog, JLayeredPane.POPUP_LAYER);
+ desktopPane.add(connectDialog, JLayeredPane.MODAL_LAYER);
errorDialog = new ErrorDialog();
errorDialog.setLocation(100, 100);
- desktopPane.add(errorDialog, JLayeredPane.POPUP_LAYER);
+ desktopPane.add(errorDialog, JLayeredPane.MODAL_LAYER);
UI.addComponent(MageComponents.DESKTOP_PANE, desktopPane);
PING_TASK_EXECUTOR.scheduleAtFixedRate(() -> SessionHandler.ping(), 60, 60, TimeUnit.SECONDS);
@@ -429,16 +429,21 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
- private boolean isChrismasTime(){
+ public static boolean isChrismasTime(Date currentTime){
// from december 15 to january 15
- Calendar cal = Calendar.getInstance();
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(currentTime);
+
int currentYear = cal.get(Calendar.YEAR);
- Date currentTime = cal.getTime();
+ if (cal.get(Calendar.MONTH) == Calendar.JANUARY){
+ currentYear = currentYear - 1;
+ }
Date chrisFrom = new GregorianCalendar(currentYear, Calendar.DECEMBER, 15).getTime();
- Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime();
+ Date chrisTo = new GregorianCalendar(currentYear + 1, Calendar.JANUARY, 15 + 1).getTime(); // end of the 15 day
- return currentTime.after(chrisFrom) && currentTime.before(chrisTo);
+ return ((currentTime.equals(chrisFrom) || currentTime.after(chrisFrom))
+ && currentTime.before(chrisTo));
}
private void addMageLabel() {
@@ -448,7 +453,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
String filename;
float ratio;
- if (isChrismasTime()){
+ if (isChrismasTime(Calendar.getInstance().getTime())){
// chrismass logo
LOGGER.info("Yo Ho Ho, Merry Christmas and a Happy New Year");
filename = "/label-xmage-christmas.png";
@@ -945,7 +950,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}//GEN-LAST:event_btnConnectActionPerformed
public void btnAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAboutActionPerformed
- JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.POPUP_LAYER);
+ JInternalFrame[] windows = desktopPane.getAllFramesInLayer(JLayeredPane.MODAL_LAYER);
for (JInternalFrame window : windows) {
if (window instanceof AboutDialog) {
// don't open the window twice.
@@ -953,7 +958,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
AboutDialog aboutDialog = new AboutDialog();
- desktopPane.add(aboutDialog, JLayeredPane.POPUP_LAYER);
+ desktopPane.add(aboutDialog, JLayeredPane.MODAL_LAYER);
aboutDialog.showDialog(VERSION);
}//GEN-LAST:event_btnAboutActionPerformed
@@ -1096,7 +1101,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
public void showUserRequestDialog(final UserRequestMessage userRequestMessage) {
final UserRequestDialog userRequestDialog = new UserRequestDialog();
userRequestDialog.setLocation(100, 100);
- desktopPane.add(userRequestDialog, JLayeredPane.POPUP_LAYER);
+ desktopPane.add(userRequestDialog, JLayeredPane.MODAL_LAYER);
if (SwingUtilities.isEventDispatchThread()) {
userRequestDialog.showDialog(userRequestMessage);
} else {
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form
index 478bd33dc4..d5ab60e950 100644
--- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form
+++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.form
@@ -500,6 +500,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java
index d889a61e12..80c5600598 100644
--- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java
+++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java
@@ -55,6 +55,7 @@ import mage.client.util.GUISizeHelper;
import mage.client.util.gui.FastSearchUtil;
import mage.client.util.sets.ConstructedFormats;
import mage.constants.CardType;
+import mage.constants.Rarity;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
@@ -214,8 +215,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
this.cards.add(card);
}
filterCards();
- }
-
+ }
+
public void loadCards(BigCard bigCard) {
this.bigCard = bigCard;
this.btnBooster.setVisible(true);
@@ -225,7 +226,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// cbExpansionSet.setModel(new DefaultComboBoxModel<>(ConstructedFormats.getTypes()));
// Action event on Expansion set triggers loadCards method
cbExpansionSet.setSelectedIndex(0);
- }
+ }
private FilterCard buildFilter() {
FilterCard filter = new FilterCard();
@@ -328,6 +329,24 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
// criteria.types(CardType.TRIBAL);
// criteria.types(CardType.CONSPIRACY);
+ if (this.tbCommon.isSelected()) {
+ criteria.rarities(Rarity.COMMON);
+ criteria.rarities(Rarity.LAND);
+ }
+ if (this.tbUncommon.isSelected()) {
+ criteria.rarities(Rarity.UNCOMMON);
+ }
+ if (this.tbRare.isSelected()) {
+ criteria.rarities(Rarity.RARE);
+ }
+ if (this.tbMythic.isSelected()) {
+ criteria.rarities(Rarity.MYTHIC);
+ }
+ if (this.tbSpecial.isSelected()) {
+ criteria.rarities(Rarity.SPECIAL);
+ criteria.rarities(Rarity.BONUS);
+ }
+
if (this.cbExpansionSet.isVisible()) {
String expansionSelection = this.cbExpansionSet.getSelectedItem().toString();
if (!expansionSelection.equals("- All Sets")) {
@@ -376,6 +395,19 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
filterCards();
}
+ private void filterCardsRarity(int modifiers, String actionCommand) {
+ // ALT or CTRL button was pushed
+ if ((modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK || (modifiers & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
+ boolean invert = (modifiers & ActionEvent.ALT_MASK) == ActionEvent.ALT_MASK;
+ tbCommon.setSelected(inverter(invert, tbCommon.getActionCommand(), actionCommand));
+ tbUncommon.setSelected(inverter(invert, tbUncommon.getActionCommand(), actionCommand));
+ tbRare.setSelected(inverter(invert, tbRare.getActionCommand(), actionCommand));
+ tbMythic.setSelected(inverter(invert, tbMythic.getActionCommand(), actionCommand));
+ tbSpecial.setSelected(inverter(invert, tbSpecial.getActionCommand(), actionCommand));
+ }
+ filterCards();
+ }
+
private void filterCards() {
FilterCard filter = buildFilter();
try {
@@ -494,6 +526,13 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
jSeparator4 = new javax.swing.JToolBar.Separator();
jToggleListView = new javax.swing.JToggleButton();
jToggleCardView = new javax.swing.JToggleButton();
+ jSeparator5 = new javax.swing.JToolBar.Separator();
+ tbRarities = new javax.swing.JToolBar();
+ tbCommon = new javax.swing.JToggleButton();
+ tbUncommon = new javax.swing.JToggleButton();
+ tbRare = new javax.swing.JToggleButton();
+ tbMythic = new javax.swing.JToggleButton();
+ tbSpecial = new javax.swing.JToggleButton();
cardSelectorScrollPane = new javax.swing.JScrollPane();
cardSelectorBottomPanel = new javax.swing.JPanel();
jButtonAddToMain = new javax.swing.JButton();
@@ -841,6 +880,88 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
}
});
tbTypes.add(jToggleCardView);
+ tbTypes.add(jSeparator5);
+
+ tbRarities.setFloatable(false);
+ tbRarities.setRollover(true);
+ tbRarities.setToolTipText("Hold the ALT-key while clicking to deselect all other card rarities or hold the CTRL-key to only select all other card rarities.");
+
+ tbCommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_common_20.png"))); // NOI18N
+ tbCommon.setSelected(true);
+ tbCommon.setToolTipText("Common
"
+ + tbRarities.getToolTipText());
+ tbCommon.setActionCommand("Common");
+ tbCommon.setFocusable(false);
+ tbCommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ tbCommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+ tbCommon.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ tbCommonActionPerformed(evt);
+ }
+ });
+ tbRarities.add(tbCommon);
+
+ tbUncommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_uncommon_20.png"))); // NOI18N
+ tbUncommon.setSelected(true);
+ tbUncommon.setToolTipText("Uncommon
"
+ + tbUncommon.getToolTipText());
+ tbUncommon.setActionCommand("Uncommon");
+ tbUncommon.setFocusable(false);
+ tbUncommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ tbUncommon.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+ tbUncommon.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ tbUncommonActionPerformed(evt);
+ }
+ });
+ tbRarities.add(tbUncommon);
+
+ tbRare.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_rare_20.png"))); // NOI18N
+ tbRare.setSelected(true);
+ tbRare.setToolTipText("Rare
"
+ + tbRarities.getToolTipText());
+ tbRare.setActionCommand("Rare");
+ tbRare.setFocusable(false);
+ tbRare.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ tbRare.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+ tbRare.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ tbRareActionPerformed(evt);
+ }
+ });
+ tbRarities.add(tbRare);
+
+ tbMythic.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_mythic_20.png"))); // NOI18N
+ tbMythic.setSelected(true);
+ tbMythic.setToolTipText("Mythic
"
+ + tbRarities.getToolTipText());
+ tbMythic.setActionCommand("Mythic");
+ tbMythic.setFocusable(false);
+ tbMythic.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ tbMythic.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+ tbMythic.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ tbMythicActionPerformed(evt);
+ }
+ });
+ tbRarities.add(tbMythic);
+
+ tbSpecial.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_special_20.png"))); // NOI18N
+ tbSpecial.setSelected(true);
+ tbSpecial.setToolTipText("Special
"
+ + tbRarities.getToolTipText());
+ tbSpecial.setActionCommand("Special");
+ tbSpecial.setFocusable(false);
+ tbSpecial.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+ tbSpecial.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+ tbSpecial.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ tbSpecialActionPerformed(evt);
+ }
+ });
+ tbRarities.add(tbSpecial);
+
+ tbTypes.add(tbRarities);
cardSelectorScrollPane.setToolTipText("Double click to add the card to the main deck.
\nALT + Double click to add the card to the sideboard.");
@@ -1224,6 +1345,26 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
FastSearchUtil.showFastSearchForStringComboBox(cbExpansionSet, "Select set or expansion");
}//GEN-LAST:event_btnExpansionSearchActionPerformed
+ private void tbCommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbCommonActionPerformed
+ filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
+ }//GEN-LAST:event_tbCommonActionPerformed
+
+ private void tbUncommonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbUncommonActionPerformed
+ filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
+ }//GEN-LAST:event_tbUncommonActionPerformed
+
+ private void tbRareActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbRareActionPerformed
+ filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
+ }//GEN-LAST:event_tbRareActionPerformed
+
+ private void tbMythicActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbMythicActionPerformed
+ filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
+ }//GEN-LAST:event_tbMythicActionPerformed
+
+ private void tbSpecialActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tbSpecialActionPerformed
+ filterCardsRarity(evt.getModifiers(), evt.getActionCommand());
+ }//GEN-LAST:event_tbSpecialActionPerformed
+
private void toggleViewMode() {
if (currentView instanceof CardGrid) {
jToggleListView.setSelected(true);
@@ -1288,6 +1429,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator4;
+ private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JToolBar.Separator jSeparator6;
private javax.swing.JTextField jTextFieldSearch;
private javax.swing.JToggleButton jToggleCardView;
@@ -1297,15 +1439,21 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
private javax.swing.JToggleButton tbBlue;
private javax.swing.JToolBar tbColor;
private javax.swing.JToggleButton tbColorless;
+ private javax.swing.JToggleButton tbCommon;
private javax.swing.JToggleButton tbCreatures;
private javax.swing.JToggleButton tbEnchantments;
private javax.swing.JToggleButton tbGreen;
private javax.swing.JToggleButton tbInstants;
private javax.swing.JToggleButton tbLand;
+ private javax.swing.JToggleButton tbMythic;
private javax.swing.JToggleButton tbPlaneswalkers;
+ private javax.swing.JToggleButton tbRare;
+ private javax.swing.JToolBar tbRarities;
private javax.swing.JToggleButton tbRed;
private javax.swing.JToggleButton tbSorceries;
+ private javax.swing.JToggleButton tbSpecial;
private javax.swing.JToolBar tbTypes;
+ private javax.swing.JToggleButton tbUncommon;
private javax.swing.JToggleButton tbWhite;
// End of variables declaration//GEN-END:variables
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java
index 623b5a434d..d89b6568cc 100644
--- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java
+++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java
@@ -465,6 +465,12 @@ public class MageBook extends JComponent {
LinkedList haveNumbers = new LinkedList<>();
for (ExpansionSet.SetCardInfo card: cards){
int cardNumber = card.getCardNumberAsInt();
+
+ // skip xmage special numbers for cards (TODO: replace full art cards numbers from 180+20 to 180b, 180c and vice versa like scryfall)
+ if(cardNumber > 500){
+ continue;
+ }
+
startNumber = min(startNumber, cardNumber);
endNumber = Math.max(endNumber, cardNumber);
haveNumbers.add(cardNumber);
diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form
index c5cfd83672..85bb3611aa 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form
+++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form
@@ -32,52 +32,39 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -85,9 +72,9 @@
-
-
-
+
+
+
@@ -128,19 +115,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -227,5 +202,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java
index 1220c61867..cb39ef8eb8 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java
@@ -44,6 +44,7 @@ import mage.cards.repository.ExpansionInfo;
import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.constants.Constants.DeckEditorMode;
+import mage.client.util.gui.FastSearchUtil;
import mage.constants.Rarity;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
@@ -113,7 +114,14 @@ public class AddLandDialog extends MageDialog {
}
cbLandSet.setModel(new DefaultComboBoxModel(landSetNames.toArray()));
- MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+
+ // windows settings
+ if (this.isModal()){
+ MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
+ }else{
+ MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ }
+
this.setVisible(true);
}
@@ -157,7 +165,6 @@ public class AddLandDialog extends MageDialog {
jButton2 = new javax.swing.JButton();
lblLandSet = new javax.swing.JLabel();
- cbLandSet = new javax.swing.JComboBox();
lblForest = new javax.swing.JLabel();
spnForest = new javax.swing.JSpinner();
lblIsland = new javax.swing.JLabel();
@@ -171,14 +178,15 @@ public class AddLandDialog extends MageDialog {
btnAdd = new javax.swing.JButton();
btnCancel = new javax.swing.JButton();
btnAutoAdd = new javax.swing.JButton();
+ panelSet = new javax.swing.JPanel();
+ cbLandSet = new javax.swing.JComboBox();
+ btnSetFastSearch = new javax.swing.JButton();
jButton2.setText("jButton2");
setTitle("Add Land");
- lblLandSet.setText("Set");
-
- cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+ lblLandSet.setText("Set:");
lblForest.setText("Forest");
@@ -201,13 +209,42 @@ public class AddLandDialog extends MageDialog {
spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
btnAdd.setText("Add");
- btnAdd.addActionListener(evt -> btnAddActionPerformed(evt));
+ btnAdd.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnAddActionPerformed(evt);
+ }
+ });
btnCancel.setText("Cancel");
- btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
+ btnCancel.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnCancelActionPerformed(evt);
+ }
+ });
btnAutoAdd.setText("Suggest");
- btnAutoAdd.addActionListener(evt -> btnAutoAddActionPerformed(evt));
+ btnAutoAdd.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnAutoAddActionPerformed(evt);
+ }
+ });
+
+ panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS));
+
+ cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
+ cbLandSet.setMinimumSize(new java.awt.Dimension(20, 20));
+ panelSet.add(cbLandSet);
+
+ btnSetFastSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N
+ btnSetFastSearch.setToolTipText("Search for set");
+ btnSetFastSearch.setAlignmentX(1.0F);
+ btnSetFastSearch.setPreferredSize(new java.awt.Dimension(23, 23));
+ btnSetFastSearch.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ btnSetFastSearchActionPerformed(evt);
+ }
+ });
+ panelSet.add(btnSetFastSearch);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
@@ -216,48 +253,40 @@ public class AddLandDialog extends MageDialog {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(lblIsland)
- .addComponent(lblMountain)
- .addComponent(lblForest)
- .addComponent(lblLandSet))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
- .addComponent(spnMountain, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
- .addComponent(spnIsland)
- .addComponent(spnForest))
- .addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, 207, javax.swing.GroupLayout.PREFERRED_SIZE)))
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
- .addComponent(lblSwamp)
- .addGap(14, 14, 14)
- .addComponent(spnSwamp))
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
- .addComponent(lblPains)
- .addGap(21, 21, 21)
- .addComponent(spnPlains)))
- .addGap(122, 122, 122)))
- .addContainerGap())
+ .addComponent(lblMountain)
+ .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING)
+ .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.createSequentialGroup()
- .addComponent(btnCancel)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(btnAutoAdd)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(btnAutoAdd, javax.swing.GroupLayout.DEFAULT_SIZE, 122, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnAdd)
- .addGap(0, 0, Short.MAX_VALUE))))
+ .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())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(cbLandSet, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(lblLandSet))
+ .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))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblForest)
@@ -312,6 +341,10 @@ public class AddLandDialog extends MageDialog {
autoAddLands();
}//GEN-LAST:event_btnAutoAddActionPerformed
+ private void btnSetFastSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSetFastSearchActionPerformed
+ FastSearchUtil.showFastSearchForStringComboBox(cbLandSet, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE);
+ }//GEN-LAST:event_btnSetFastSearchActionPerformed
+
private void autoAddLands() {
int red = 0;
int green = 0;
@@ -356,6 +389,7 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JButton btnAdd;
private javax.swing.JButton btnAutoAdd;
private javax.swing.JButton btnCancel;
+ private javax.swing.JButton btnSetFastSearch;
private javax.swing.JComboBox cbLandSet;
private javax.swing.JButton jButton2;
private javax.swing.JLabel lblForest;
@@ -364,6 +398,7 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JLabel lblMountain;
private javax.swing.JLabel lblPains;
private javax.swing.JLabel lblSwamp;
+ private javax.swing.JPanel panelSet;
private javax.swing.JSpinner spnForest;
private javax.swing.JSpinner spnIsland;
private javax.swing.JSpinner spnMountain;
diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
index 4cb7a20ec8..867698822d 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java
@@ -102,10 +102,10 @@ public class ConnectDialog extends MageDialog {
this.txtPassword.addActionListener(connectAction);
registerUserDialog = new RegisterUserDialog(this);
- MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.POPUP_LAYER);
+ MageFrame.getDesktop().add(registerUserDialog, JLayeredPane.MODAL_LAYER);
resetPasswordDialog = new ResetPasswordDialog(this);
- MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.POPUP_LAYER);
+ MageFrame.getDesktop().add(resetPasswordDialog, JLayeredPane.MODAL_LAYER);
}
public void showDialog() {
@@ -744,7 +744,7 @@ public class ConnectDialog extends MageDialog {
DefaultComboBoxModel flagModel = (DefaultComboBoxModel)cbFlag.getModel();
String[] flagItem;
- for(int i = 0; i < flagModel.getSize() - 1; i++){
+ for(int i = 0; i < flagModel.getSize(); i++){
flagItem = (String[])flagModel.getElementAt(i);
choiceItems.put(flagItem[1], flagItem[0]);
}
diff --git a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java
index ef6e29b426..5deaed81aa 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java
@@ -45,8 +45,8 @@ import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
-import javax.swing.JComponent;
-import javax.swing.SwingUtilities;
+import javax.swing.*;
+
import mage.client.MageFrame;
import org.apache.log4j.Logger;
@@ -74,11 +74,34 @@ public class MageDialog extends javax.swing.JInternalFrame {
@Override
public void show() {
super.show();
- this.toFront();
+
+ // frames desktop ordering
+ // more info https://docs.oracle.com/javase/7/docs/api/javax/swing/JLayeredPane.html
+ // WARNING, use
+ // - JLayeredPane.DEFAULT_LAYER: tables and games (tabs)
+ // - JLayeredPane.PALETTE_LAYER: toolbars and info windows like cards list, not modal dialogs (not required user actions)
+ // - JLayeredPane.MODAL_LAYER: all modal dialogs (user required actions - select cards in game, new game window, error windows)
+ // - JLayeredPane.POPUP_LAYER: hints and other top level graphics
+ // - JLayeredPane.DRAG_LAYER: top most layer for critical actions and user controls
+ /*
+ JInternalFrame[] frames = MageFrame.getDesktop().getAllFrames();
+ System.out.println("---");
+ for(JInternalFrame frame: frames){
+ int zorder = -1;
+ if (frame.getParent() != null){
+ frame.getParent().getComponentZOrder(frame);
+ }
+ System.out.println(frame.getClass() + " (" + frame.getTitle() + ") : layer = " + frame.getLayer() + ", zorder = " + zorder);
+ }
+ */
+
if (modal) {
this.setClosable(false);
}
- if (this.modal) {
+
+ this.toFront();
+
+ if (modal){
startModal();
}
}
@@ -108,7 +131,6 @@ public class MageDialog extends javax.swing.JInternalFrame {
}
private synchronized void startModal() {
-
try {
if (SwingUtilities.isEventDispatchThread()) {
EventQueue theQueue = getToolkit().getSystemEventQueue();
diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java
index 5842ca7514..17a376f4dc 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java
@@ -47,6 +47,7 @@ import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.table.TournamentPlayerPanel;
+import mage.client.util.gui.FastSearchUtil;
import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
@@ -76,7 +77,7 @@ public class NewTournamentDialog extends MageDialog {
private RandomPacksSelectorDialog randomPackSelector;
private JTextArea txtRandomPacks;
private final List players = new ArrayList<>();
- private final List packs = new ArrayList<>();
+ private final List packPanels = new ArrayList<>();
private static final int CONSTRUCTION_TIME_MIN = 6;
private static final int CONSTRUCTION_TIME_MAX = 30;
private boolean isRandom = false;
@@ -586,8 +587,13 @@ public class NewTournamentDialog extends MageDialog {
tOptions.getLimitedOptions().getSetCodes().addAll(selected);
}
} else {
- for (JComboBox pack : packs) {
- tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) pack.getSelectedItem()).getCode());
+ for (JPanel panel : packPanels) {
+ JComboBox combo = findComboInComponent(panel);
+ if(combo != null) {
+ tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode());
+ }else{
+ logger.error("Can't find combo component in " + panel.toString());
+ }
}
}
tOptions.getMatchOptions().setDeckType("Limited");
@@ -884,35 +890,89 @@ public class NewTournamentDialog extends MageDialog {
}
private void createPacks(int numPacks) {
- while (packs.size() > numPacks) {
- pnlPacks.remove(packs.get(packs.size() - 1));
- packs.remove(packs.size() - 1);
+ while (packPanels.size() > numPacks) {
+ pnlPacks.remove(packPanels.get(packPanels.size() - 1));
+ packPanels.remove(packPanels.size() - 1);
}
- while (packs.size() < numPacks) {
+ while (packPanels.size() < numPacks) {
+ // SELECT PACK
+ // panel
+ JPanel setPanel = new JPanel();
+ setPanel.setLayout(new javax.swing.BoxLayout(setPanel, javax.swing.BoxLayout.LINE_AXIS));
+ setPanel.setOpaque(false);
+ //setPanel.setPreferredSize(new Dimension(200, 25));
+ //setPanel.setMaximumSize(new Dimension(200, 25));
+ pnlPacks.add(setPanel);
+ packPanels.add(setPanel); // for later access
+ // combo set
JComboBox pack = new JComboBox();
+ pack = new JComboBox();
pack.setModel(new DefaultComboBoxModel(ExpansionRepository.instance.getWithBoostersSortedByReleaseDate()));
- pnlPacks.add(pack);
- packs.add(pack);
pack.addActionListener(evt -> packActionPerformed(evt));
+ pack.setAlignmentX(0.0F);
+ pack.setMinimumSize(new Dimension(50, 25));
+ pack.setPreferredSize(new Dimension(50, 25));
+ pack.setMaximumSize(new Dimension(Integer.MAX_VALUE, 25));
+ setPanel.add(pack);
+ // search button
+ JButton searchButton = new JButton();
+ searchButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png")));
+ searchButton.setToolTipText("Search and select from list");
+ searchButton.setAlignmentX(1.0F);
+ searchButton.setMinimumSize(new java.awt.Dimension(24, 24));
+ searchButton.setPreferredSize(new java.awt.Dimension(32, 32));
+ searchButton.setMaximumSize(new java.awt.Dimension(32, 32));
+ searchButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+
+ // search combo box near button (must be only one combo in panel)
+ JButton button = (JButton)evt.getSource();
+ JComboBox combo = findComboInComponent(button.getParent());
+
+ if (combo != null) {
+ FastSearchUtil.showFastSearchForStringComboBox(combo, "Select value");
+ }
+ }
+ });
+ setPanel.add(searchButton);
}
this.pack();
this.revalidate();
this.repaint();
}
- private void packActionPerformed(java.awt.event.ActionEvent evt) {
- boolean start = false;
- int selectedIndex = 0;
- for (JComboBox pack : packs) {
- if (!start) {
- if (evt.getSource().equals(pack)) {
- start = true;
- selectedIndex = pack.getSelectedIndex();
- }
- } else {
- pack.setSelectedIndex(selectedIndex);
+ private JComboBox findComboInComponent(Container panel){
+ // search combo box near button (must be only one combo in panel)
+ JComboBox combo = null;
+ for(Component comp: panel.getComponents()){
+ if (comp instanceof JComboBox){
+ combo = (JComboBox)comp;
+ break;
}
}
+ return combo;
+ }
+
+ private void packActionPerformed(java.awt.event.ActionEvent evt) {
+ // fill all bottom combobox with same value
+ JComboBox curentCombo = (JComboBox)evt.getSource();
+ int newValue = curentCombo.getSelectedIndex();
+
+ // search start index
+ int startIndex = 0;
+ for(int i = 0; i < packPanels.size(); i++){
+ JComboBox pack = findComboInComponent(packPanels.get(i));
+ if (pack.equals(curentCombo)){
+ startIndex = i + 1;
+ break;
+ }
+ }
+
+ // change all from start index
+ for(int i = startIndex; i < packPanels.size(); i++){
+ JComboBox pack = findComboInComponent(packPanels.get(i));
+ pack.setSelectedIndex(newValue);
+ }
}
private void createPlayers(int numPlayers) {
@@ -1054,16 +1114,22 @@ public class NewTournamentDialog extends MageDialog {
int packNumber = 0;
for (String pack : packsArray) {
packNumber++;
- if (this.packs.size() >= packNumber - 1) {
- JComboBox comboBox = this.packs.get(packNumber - 1);
- ComboBoxModel model = comboBox.getModel();
- int size = model.getSize();
- for (int i = 0; i < size; i++) {
- ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
- if (element.getCode().equals(pack.trim())) {
- comboBox.setSelectedIndex(i);
- break;
+ if (this.packPanels.size() >= packNumber - 1) {
+ JPanel panel = packPanels.get(packNumber - 1);
+ JComboBox comboBox = findComboInComponent(panel);
+
+ if (comboBox != null) {
+ ComboBoxModel model = comboBox.getModel();
+ int size = model.getSize();
+ for (int i = 0; i < size; i++) {
+ ExpansionInfo element = (ExpansionInfo) model.getElementAt(i);
+ if (element.getCode().equals(pack.trim())) {
+ comboBox.setSelectedIndex(i);
+ break;
+ }
}
+ }else{
+ logger.error("Can't find combo component in " + panel.toString());
}
}
diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java
index 1e5f70cda1..80a28468f9 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java
@@ -165,7 +165,11 @@ public class PickChoiceDialog extends MageDialog {
}
// window settings
- MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ if (this.isModal()){
+ MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
+ }else{
+ MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ }
if (mageDialogState != null) {
mageDialogState.setStateToDialog(this);
@@ -174,14 +178,14 @@ public class PickChoiceDialog extends MageDialog {
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);
}
-
+
// final load
loadData();
// start selection
if((startSelectionValue != null)){
int selectIndex = -1;
- for(int i = 0; i < this.listChoices.getModel().getSize() - 1; i++){
+ for(int i = 0; i < this.listChoices.getModel().getSize(); i++){
KeyValueItem listItem = (KeyValueItem)this.listChoices.getModel().getElementAt(i);
if (listItem.Key.equals(startSelectionValue)){
selectIndex = i;
diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java
index 018c2bb44e..f4e3244fb1 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java
@@ -35,7 +35,9 @@
package mage.client.dialog;
import java.awt.Point;
-import javax.swing.SpinnerNumberModel;
+import javax.swing.*;
+
+import mage.client.MageFrame;
import mage.client.util.SettingsManager;
import mage.client.util.gui.GuiDisplayUtil;
@@ -60,6 +62,13 @@ public class PickNumberDialog extends MageDialog {
this.btnCancel.setVisible(false);
this.pack();
+ // window settings
+ if (this.isModal()){
+ MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
+ }else{
+ MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ }
+
Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight());
this.setLocation(centered.x, centered.y);
GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this);
diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java
index 9fcfdfdd24..ff3682272c 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java
@@ -114,6 +114,14 @@ public class PickPileDialog extends MageDialog {
this.revalidate();
this.repaint();
this.setModal(true);
+
+ // window settings
+ if (this.isModal()){
+ MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
+ }else{
+ MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ }
+
this.setVisible(true);
}
diff --git a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java
index d26d318012..f185bf2556 100644
--- a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java
+++ b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java
@@ -120,15 +120,19 @@ public class ShowCardsDialog extends MageDialog {
this.cardArea.addCardEventListener(eventListener);
}
- if (getParent() != MageFrame.getDesktop() /*|| this.isClosed*/) {
- MageFrame.getDesktop().add(this, JLayeredPane.DEFAULT_LAYER);
- }
pack();
this.revalidate();
this.repaint();
this.setModal(modal);
+ // window settings
+ if (this.isModal()){
+ MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER);
+ }else{
+ MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
+ }
+
SwingUtilities.invokeLater(() -> {
if (!positioned) {
int width = ShowCardsDialog.this.getWidth();
diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java
index ab0daf3e70..3509af9c28 100644
--- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java
+++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java
@@ -1115,7 +1115,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
this.feedbackPanel.getFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId);
if (dialog != null) {
- this.pickTarget.add(dialog);
+ this.pickTarget.add(dialog); // TODO: 01.01.2018, JayDi85: why feedbackPanel saved to pickTarget list? Need to research
}
}
diff --git a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java
index 9d88e27137..ed54815434 100644
--- a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java
+++ b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java
@@ -32,8 +32,8 @@ public class FastSearchUtil {
Map choiceSorting = new HashMap<>(comboModel.getSize());
String item;
- for(int i = 0; i < comboModel.getSize() - 1; i++){
- item = (String)comboModel.getElementAt(i);
+ for(int i = 0; i < comboModel.getSize(); i++){
+ item = comboModel.getElementAt(i).toString();
choiceItems.put(item, item);
choiceSorting.put(item, i); // need so sorting
}
@@ -44,7 +44,7 @@ public class FastSearchUtil {
// current selection value restore
String needSelectValue;
- needSelectValue = (String)comboModel.getSelectedItem();
+ needSelectValue = comboModel.getSelectedItem().toString();
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
@@ -52,7 +52,13 @@ public class FastSearchUtil {
dlg.showDialog(choice, needSelectValue);
if(choice.isChosen()){
item = choice.getChoiceKey();
- comboModel.setSelectedItem(item);
+
+ // compatible select for object's models (use setSelectedIndex instead setSelectedObject)
+ for(int i = 0; i < comboModel.getSize(); i++){
+ if(comboModel.getElementAt(i).toString().equals(item)){
+ combo.setSelectedIndex(i);
+ }
+ }
}
}
}
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java
index d29a7d113d..7642f87d96 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java
@@ -253,6 +253,7 @@ public enum MythicspoilerComSource implements CardImageSource {
supportedSets.add("C17");
supportedSets.add("IMA");
supportedSets.add("XLN");
+ supportedSets.add("UST");
supportedSets.add("RIX");
sets = new LinkedHashMap<>();
@@ -280,7 +281,8 @@ public enum MythicspoilerComSource implements CardImageSource {
cardNameAliases.put("XLN-lookoutsdecision", "lookoutsdispersal");
cardNameAliases.put("XLN-infuriatedgladiodon", "ragingswordtooth");
cardNameAliases.put("XLN-redoubledvolley", "repeatingbarrage");
-
+ cardNameAliases.put("UST-captialoffense", "capitaloffense");
+ cardNameAliases.put("RIX-tetzimocdeathprimordial", "tetzimocprimaldeath");
//
manualLinks = new HashMap<>();
HashMap links = new HashMap<>();
@@ -417,6 +419,8 @@ public enum MythicspoilerComSource implements CardImageSource {
Map setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
String searchName = card.getDownloadName().toLowerCase()
.replaceAll(" ", "")
+ .replaceAll("\\.", "")
+ .replaceAll("&", "and")
.replaceAll("-", "")
.replaceAll("'", "")
.replaceAll(",", "")
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java
index efc266a49e..d98997a7c5 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java
@@ -45,6 +45,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.prefs.Preferences;
+import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
@@ -265,7 +266,7 @@ public enum WizardCardsImageSource implements CardImageSource {
supportedSets.add("IMA"); // Iconic Msters
supportedSets.add("E02"); // Explorers of Ixalan
supportedSets.add("V17"); // From the Vault: Transform
-// supportedSets.add("UST"); // Unstable
+ supportedSets.add("UST"); // Unstable
// supportedSets.add("RIX"); // Rivals of Ixalan
// supportedSets.add("A25"); // Masters 25
// supportedSets.add("DOM"); // Dominaria
@@ -363,6 +364,7 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("HOP", "Planechase");
setsAliases.put("HOU", "Hour of Devastation");
setsAliases.put("ICE", "Ice Age");
+ setsAliases.put("IMA", "Iconic Masters");
setsAliases.put("INV", "Invasion");
setsAliases.put("ISD", "Innistrad");
setsAliases.put("JOU", "Journey into Nyx");
@@ -455,7 +457,6 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("WMCQ", "World Magic Cup Qualifier");
setsAliases.put("WTH", "Weatherlight");
setsAliases.put("WWK", "Worldwake");
- setsAliases.put("XLN", "Ixalan");
setsAliases.put("ZEN", "Zendikar");
languageAliases = new HashMap<>();
@@ -487,43 +488,44 @@ public enum WizardCardsImageSource implements CardImageSource {
if (card.isFlippedSide()) { //doesn't support rotated images
return null;
}
- String setNames = setsAliases.get(cardSet);
- if (setNames != null) {
- Map setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
- if (setLinks == null || setLinks.isEmpty()) {
- return null;
- }
- String link = setLinks.get(card.getDownloadName().toLowerCase());
- if (link == null) {
- int length = collectorId.length();
- if (Character.isLetter(collectorId.charAt(length - 1))) {
- length -= 1;
- }
- int number = Integer.parseInt(collectorId.substring(0, length));
- if (number > 0) {
- String key = card.getDownloadName().toLowerCase() + number;
- link = setLinks.get(key);
- }
+ Map setLinks = sets.computeIfAbsent(cardSet, k -> getSetLinks(cardSet));
+ if (setLinks == null || setLinks.isEmpty()) {
+ return null;
+ }
+ String searchKey = card.getDownloadName().toLowerCase().replace(" ", "").replace("&", "//");
+ String link = setLinks.get(searchKey);
+ if (link == null) {
+ int length = collectorId.length();
+ // Try to find card image with added letter (e.g. from Unstable)
+ if (Character.isLetter(collectorId.charAt(length - 1))) {
+ String key = searchKey + collectorId.charAt(length - 1);
+ link = setLinks.get(key);
+ }
+ // Try to find image with added card number (e.g. basic lands)
+ if (link == null) {
+ String key = searchKey + collectorId;
+ link = setLinks.get(key);
if (link == null) {
- List l = new ArrayList<>(setLinks.values());
- if (l.size() >= number) {
- link = l.get(number - 1);
- } else {;
- link = l.get(number - 21);
- if (link != null) {
- link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
+ int number = Integer.parseInt(collectorId.substring(0, length));
+ if (number > 0) {
+ List l = new ArrayList<>(setLinks.values());
+ if (l.size() >= number) {
+ link = l.get(number - 1);
+ } else {;
+ link = l.get(number - 21);
+ if (link != null) {
+ link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
+ }
}
}
}
}
- if (link != null && !link.startsWith("http://")) {
- link = "http://gatherer.wizards.com" + link;
- }
- return link;
}
-
- return null;
+ if (link != null && !link.startsWith("http://")) {
+ link = "http://gatherer.wizards.com" + link;
+ }
+ return link;
}
@@ -532,6 +534,9 @@ public enum WizardCardsImageSource implements CardImageSource {
ExecutorService executor = Executors.newFixedThreadPool(10);
try {
String setNames = setsAliases.get(cardSet);
+ if (setNames == null) {
+ setNames = Sets.getInstance().get(cardSet).getName();
+ }
String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
for (String setName : setNames.split("\\^")) {
// String URLSetName = URLEncoder.encode(setName, "UTF-8");
@@ -557,11 +562,21 @@ public enum WizardCardsImageSource implements CardImageSource {
}
String cardName = normalizeName(cardsImages.get(i).attr("alt"));
if (cardName != null && !cardName.isEmpty()) {
- if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) {
+ if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island")
+ || cardName.equals("Plains") || cardName.equals("Wastes")) {
getLandVariations(setLinks, cardSet, multiverseId, cardName);
} else {
+ String numberChar = "";
+ int pos1 = cardName.indexOf("(");
+ if (pos1 > 0) {
+ int pos2 = cardName.indexOf("(", pos1 + 1);
+ if (pos2 > 0) {
+ numberChar = cardName.substring(pos2 + 1, pos2 + 2);
+ cardName = cardName.substring(0, pos1);
+ }
+ }
Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
- setLinks.put(cardName.toLowerCase(), generateLink(preferedMultiverseId));
+ setLinks.put(cardName.toLowerCase() + numberChar, generateLink(preferedMultiverseId));
}
}
}
@@ -613,7 +628,7 @@ public enum WizardCardsImageSource implements CardImageSource {
private void getLandVariations(LinkedHashMap setLinks, String cardSet, int multiverseId, String cardName) throws IOException, NumberFormatException {
CardCriteria criteria = new CardCriteria();
- criteria.name(cardName);
+ criteria.nameExact(cardName);
criteria.setCodes(cardSet);
List cards = CardRepository.instance.findCards(criteria);
@@ -697,7 +712,9 @@ public enum WizardCardsImageSource implements CardImageSource {
.replace("\u00DB", "U").replace("\u00FB", "u")
.replace("\u00DC", "U").replace("\u00FC", "u")
.replace("\u00E9", "e").replace("&", "//")
+ .replace(" ", "")
.replace("Hintreland Scourge", "Hinterland Scourge");
+
}
@Override
diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java
index e89c415880..5850cbcc3c 100644
--- a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java
+++ b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java
@@ -4,7 +4,6 @@ import java.io.File;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
-import java.util.Objects;
import java.util.prefs.Preferences;
import mage.client.MageFrame;
import mage.client.constants.Constants;
@@ -122,17 +121,17 @@ public final class CardImageUtils {
return set;
}
- public static String prepareCardNameForFile(String cardName){
+ public static String prepareCardNameForFile(String cardName) {
return cardName.replace(":", "").replace("\"", "").replace("//", "-");
}
- public static String getImagesDir(){
+ public static String getImagesDir() {
// return real images dir (path without separator)
String path = null;
// user path
- if (!PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true").equals("true")){
+ if (!PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true").equals("true")) {
path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
}
@@ -141,8 +140,7 @@ public final class CardImageUtils {
path = Constants.IO.DEFAULT_IMAGES_DIR;
}
- while(path.endsWith(File.separator))
- {
+ while (path.endsWith(File.separator)) {
path = path.substring(0, path.length() - 1);
}
@@ -152,7 +150,6 @@ public final class CardImageUtils {
public static String buildImagePathToTokens() {
String imagesPath = getImagesDir() + File.separator;
-
if (PreferencesDialog.isSaveImagesToZip()) {
return imagesPath + "TOK.zip" + File.separator;
} else {
@@ -198,20 +195,25 @@ public final class CardImageUtils {
String setPath = buildImagePathToSet(card);
String prefixType = "";
- if(card.getType() != 0){
+ if (card.getType() != 0) {
prefixType = " " + Integer.toString(card.getType());
}
String cardName = card.getFileName();
- if (cardName.isEmpty()){
+ if (cardName.isEmpty()) {
cardName = prepareCardNameForFile(card.getName());
}
String finalFileName = "";
- if (card.getUsesVariousArt()){
+ if (card.getUsesVariousArt()) {
finalFileName = cardName + '.' + card.getCollectorId() + ".full.jpg";
- }else{
- finalFileName = cardName + prefixType + ".full.jpg";
+ } else {
+ int len = card.getCollectorId().length();
+ if (Character.isLetter(card.getCollectorId().charAt(len - 1))) {
+ finalFileName = cardName + card.getCollectorId().charAt(len - 1) + ".full.jpg";
+ } else {
+ finalFileName = cardName + prefixType + ".full.jpg";
+ }
}
// if image file exists, correct name (for case sensitive systems)
@@ -219,17 +221,17 @@ public final class CardImageUtils {
TFile dirFile = new TFile(setPath);
TFile imageFile = new TFile(setPath + finalFileName);
// warning, zip files can be broken
- try{
+ try {
if (dirFile.exists() && !imageFile.exists()) {
// search like names
- for (String fileName: dirFile.list()) {
+ for (String fileName : dirFile.list()) {
if (fileName.toLowerCase().equals(finalFileName.toLowerCase())) {
finalFileName = fileName;
break;
}
}
}
- }catch (Exception ex) {
+ } catch (Exception ex) {
log.error("Can't read card name from file, may be it broken: " + setPath);
}
diff --git a/Mage.Client/src/main/resources/buttons/rarity_common_20.png b/Mage.Client/src/main/resources/buttons/rarity_common_20.png
new file mode 100644
index 0000000000..c14d97d262
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_common_20.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_common_32.png b/Mage.Client/src/main/resources/buttons/rarity_common_32.png
new file mode 100644
index 0000000000..af0dabcfbd
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_common_32.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_mythic_20.png b/Mage.Client/src/main/resources/buttons/rarity_mythic_20.png
new file mode 100644
index 0000000000..599cd9c689
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_mythic_20.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_mythic_32.png b/Mage.Client/src/main/resources/buttons/rarity_mythic_32.png
new file mode 100644
index 0000000000..125a887cd4
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_mythic_32.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_rare_20.png b/Mage.Client/src/main/resources/buttons/rarity_rare_20.png
new file mode 100644
index 0000000000..5079f6b661
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_rare_20.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_rare_32.png b/Mage.Client/src/main/resources/buttons/rarity_rare_32.png
new file mode 100644
index 0000000000..c07b81c1fd
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_rare_32.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_special_20.png b/Mage.Client/src/main/resources/buttons/rarity_special_20.png
new file mode 100644
index 0000000000..f66964a13b
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_special_20.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_special_32.png b/Mage.Client/src/main/resources/buttons/rarity_special_32.png
new file mode 100644
index 0000000000..8c7740a8f2
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_special_32.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_uncommon_20.png b/Mage.Client/src/main/resources/buttons/rarity_uncommon_20.png
new file mode 100644
index 0000000000..e0c8bcb929
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_uncommon_20.png differ
diff --git a/Mage.Client/src/main/resources/buttons/rarity_uncommon_32.png b/Mage.Client/src/main/resources/buttons/rarity_uncommon_32.png
new file mode 100644
index 0000000000..77b1428879
Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/rarity_uncommon_32.png differ
diff --git a/Mage.Client/src/test/java/mage/client/util/ChrismasTest.java b/Mage.Client/src/test/java/mage/client/util/ChrismasTest.java
new file mode 100644
index 0000000000..93d4b26c70
--- /dev/null
+++ b/Mage.Client/src/test/java/mage/client/util/ChrismasTest.java
@@ -0,0 +1,42 @@
+package mage.client.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import static mage.client.MageFrame.isChrismasTime;
+
+public class ChrismasTest {
+
+ private Date getDate(int Year, int Month, int Day){
+ Calendar cal = new GregorianCalendar(Year, Month - 1, Day);
+ return cal.getTime();
+ }
+
+ @Test
+ public void ignoreDefaultResponse() throws Exception {
+ // chrismas from 15 december to 15 january
+ Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 1)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 15)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2017, 11, 30)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 1)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2017, 12, 14)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 15)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 16)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2017, 12, 31)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 1)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 14)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2018, 1, 15)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 16)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2018, 1, 31)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2018, 2, 1)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2018, 12, 1)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2018, 12, 20)));
+ Assert.assertEquals(true, isChrismasTime(getDate(2019, 1, 10)));
+ Assert.assertEquals(false, isChrismasTime(getDate(2019, 1, 25)));
+ }
+
+}
diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java
index 2ef3e3430b..d034e29155 100644
--- a/Mage.Common/src/main/java/mage/utils/MageVersion.java
+++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java
@@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable {
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 26;
- public final static String MAGE_VERSION_MINOR_PATCH = "V10b";
+ public final static String MAGE_VERSION_MINOR_PATCH = "V10";
public final static String MAGE_VERSION_INFO = "";
private final int major;
diff --git a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java
index 6a91a5f897..31453ff15b 100644
--- a/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java
+++ b/Mage.Sets/src/mage/cards/a/ArbiterOfTheIdeal.java
@@ -119,7 +119,7 @@ class ArbiterOfTheIdealEffect extends OneShotEffect {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
permanent.addCounters(new Counter("Manifestation"), source, game);
- ContinuousEffect effect = new AddCardTypeTargetEffect(CardType.ENCHANTMENT, Duration.Custom);
+ ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ENCHANTMENT);
effect.setTargetPointer(new FixedTarget(permanent.getId()));
game.addEffect(effect, source);
}
diff --git a/Mage.Sets/src/mage/cards/a/ArgentMutation.java b/Mage.Sets/src/mage/cards/a/ArgentMutation.java
index 4f0bd3b6af..f115d399c4 100644
--- a/Mage.Sets/src/mage/cards/a/ArgentMutation.java
+++ b/Mage.Sets/src/mage/cards/a/ArgentMutation.java
@@ -46,7 +46,7 @@ public class ArgentMutation extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}");
- this.getSpellAbility().addEffect(new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn));
+ this.getSpellAbility().addEffect(new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT));
this.getSpellAbility().addTarget(new TargetPermanent());
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
}
diff --git a/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java b/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java
index d75cdec650..6c285b30c1 100644
--- a/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java
+++ b/Mage.Sets/src/mage/cards/a/AshnodsTransmogrant.java
@@ -65,7 +65,7 @@ public class AshnodsTransmogrant extends CardImpl {
// {T}, Sacrifice Ashnod's Transmogrant: Put a +1/+1 counter on target nonartifact creature. That creature becomes an artifact in addition to its other types.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
- Effect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield);
+ Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT);
effect.setText("That creature becomes an artifact in addition to its other types");
ability.addEffect(effect);
ability.addTarget(new TargetCreaturePermanent(filter));
diff --git a/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java b/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java
new file mode 100644
index 0000000000..2e00ca988e
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java
@@ -0,0 +1,93 @@
+/*
+ * 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.UUID;
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.costs.mana.ManaCostsImpl;
+import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect;
+import mage.abilities.keyword.FlyingAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.filter.common.FilterLandPermanent;
+import mage.filter.predicate.mageobject.SupertypePredicate;
+import mage.game.permanent.token.Token;
+import mage.target.TargetPermanent;
+
+/**
+ *
+ * @author TheElk801 & L_J
+ */
+public class BalduvianFrostwaker extends CardImpl {
+
+ private static final FilterLandPermanent filter = new FilterLandPermanent("snow land");
+
+ static {
+ filter.add(new SupertypePredicate(SuperType.SNOW));
+ }
+
+ public BalduvianFrostwaker(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
+ this.subtype.add(SubType.HUMAN);
+ this.subtype.add(SubType.WIZARD);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(1);
+
+ // {U}, {T}: Target snow land becomes a 2/2 blue Elemental creature with flying. It's still a land.
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect(new BalduvianFrostwakerToken(), false, true, Duration.Custom), new ManaCostsImpl("{U}"));
+ ability.addCost(new TapSourceCost());
+ ability.addTarget(new TargetPermanent(filter));
+ this.addAbility(ability);
+ }
+
+ public BalduvianFrostwaker(final BalduvianFrostwaker card) {
+ super(card);
+ }
+
+ @Override
+ public BalduvianFrostwaker copy() {
+ return new BalduvianFrostwaker(this);
+ }
+}
+
+class BalduvianFrostwakerToken extends Token {
+
+ public BalduvianFrostwakerToken() {
+ super("Elemental", "2/2 blue Elemental creature with flying");
+ this.cardType.add(CardType.CREATURE);
+ color.setBlue(true);
+ subtype.add(SubType.ELEMENTAL);
+ this.power = new MageInt(2);
+ this.toughness = new MageInt(2);
+ this.addAbility(FlyingAbility.getInstance());
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/b/BaronVonCount.java b/Mage.Sets/src/mage/cards/b/BaronVonCount.java
index 5948ab714a..36cf00d675 100644
--- a/Mage.Sets/src/mage/cards/b/BaronVonCount.java
+++ b/Mage.Sets/src/mage/cards/b/BaronVonCount.java
@@ -157,15 +157,17 @@ class BaronVonCountTriggeredAbility extends TriggeredAbilityImpl {
}
Integer doomNumber = (Integer) game.getState().getValue(mageObject.getId() + "_doom");
if (spell != null && sourcePermanent != null && mageObject != null && doomNumber > 0) {
- String doomString = doomNumber.toString();
- if (spell.getCard().getManaCost().getText().contains(doomString)
- || String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
- || String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
- return true;
- } else {
- for (String string : spell.getCard().getRules()) {
- if (string.contains(doomString)) {
- return true;
+ if (!spell.isFaceDown(game)) {
+ String doomString = doomNumber.toString();
+ if (spell.getCard().getManaCost().getText().contains(doomString)
+ || String.valueOf(spell.getPower().getBaseValue()).contains(doomString)
+ || String.valueOf(spell.getToughness().getBaseValue()).contains(doomString)) {
+ return true;
+ } else {
+ for (String string : spell.getCard().getRules()) {
+ if (string.contains(doomString)) {
+ return true;
+ }
}
}
}
diff --git a/Mage.Sets/src/mage/cards/d/DregscapeZombie.java b/Mage.Sets/src/mage/cards/d/DregscapeZombie.java
index 02eef7646f..ecd94446bf 100644
--- a/Mage.Sets/src/mage/cards/d/DregscapeZombie.java
+++ b/Mage.Sets/src/mage/cards/d/DregscapeZombie.java
@@ -25,7 +25,6 @@
* 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;
@@ -43,16 +42,17 @@ import mage.constants.SubType;
*/
public class DregscapeZombie extends CardImpl {
- public DregscapeZombie (UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}");
+ public DregscapeZombie(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
this.subtype.add(SubType.ZOMBIE);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
+ // Unearth {B} ({B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)
this.addAbility(new UnearthAbility(new ManaCostsImpl("{B}")));
}
- public DregscapeZombie (final DregscapeZombie card) {
+ public DregscapeZombie(final DregscapeZombie card) {
super(card);
}
diff --git a/Mage.Sets/src/mage/cards/e/EvenTheOdds.java b/Mage.Sets/src/mage/cards/e/EvenTheOdds.java
new file mode 100644
index 0000000000..125a314497
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/e/EvenTheOdds.java
@@ -0,0 +1,65 @@
+/*
+ * 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.e;
+
+import java.util.UUID;
+import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
+import mage.abilities.condition.common.ControlsPermanentsComparedToOpponentsCondition;
+import mage.abilities.effects.common.CreateTokenEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.filter.StaticFilters;
+import mage.game.permanent.token.SoldierToken;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class EvenTheOdds extends CardImpl {
+
+ public EvenTheOdds(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}");
+
+ // Cast Even the Odds only if you control fewer creatures than each opponent.
+ this.addAbility(new CastOnlyIfConditionIsTrueAbility(new ControlsPermanentsComparedToOpponentsCondition(ComparisonType.FEWER_THAN, StaticFilters.FILTER_PERMANENT_CREATURES)));
+
+ // Create three 1/1 white Soldier creature tokens.
+ this.getSpellAbility().addEffect(new CreateTokenEffect(new SoldierToken(), 3));
+ }
+
+ public EvenTheOdds(final EvenTheOdds card) {
+ super(card);
+ }
+
+ @Override
+ public EvenTheOdds copy() {
+ return new EvenTheOdds(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/f/FeastOfBlood.java b/Mage.Sets/src/mage/cards/f/FeastOfBlood.java
index dca065ae8f..f13592fe8c 100644
--- a/Mage.Sets/src/mage/cards/f/FeastOfBlood.java
+++ b/Mage.Sets/src/mage/cards/f/FeastOfBlood.java
@@ -28,18 +28,16 @@
package mage.cards.f;
import java.util.UUID;
-import mage.abilities.Ability;
-import mage.abilities.costs.Cost;
-import mage.abilities.costs.CostImpl;
+import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
+import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.filter.common.FilterControlledCreaturePermanent;
-import mage.filter.predicate.mageobject.SubtypePredicate;
-import mage.game.Game;
import mage.target.common.TargetCreaturePermanent;
/**
@@ -49,11 +47,14 @@ import mage.target.common.TargetCreaturePermanent;
public class FeastOfBlood extends CardImpl {
public FeastOfBlood(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}");
-
+ super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}");
// Cast Feast of Blood only if you control two or more Vampires.
- this.getSpellAbility().addCost(new FeastOfBloodCost());
+ this.addAbility(new CastOnlyIfConditionIsTrueAbility(
+ new PermanentsOnTheBattlefieldCondition(
+ new FilterControlledCreaturePermanent(SubType.VAMPIRE, "if you control two or more Vampires"),
+ ComparisonType.MORE_THAN, 1)));
+
// Destroy target creature. You gain 4 life.
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new DestroyTargetEffect());
@@ -69,36 +70,3 @@ public class FeastOfBlood extends CardImpl {
return new FeastOfBlood(this);
}
}
-
-class FeastOfBloodCost extends CostImpl {
-
- private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
-
- static {
- filter.add(new SubtypePredicate(SubType.VAMPIRE));
- }
-
- public FeastOfBloodCost() {
- this.text = "you must control two or more Vampires";
- }
-
- public FeastOfBloodCost(final FeastOfBloodCost cost) {
- super(cost);
- }
-
- @Override
- public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
- return game.getBattlefield().contains(filter, controllerId, 2, game);
- }
-
- @Override
- public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
- this.paid = true;
- return paid;
- }
-
- @Override
- public FeastOfBloodCost copy() {
- return new FeastOfBloodCost(this);
- }
-}
diff --git a/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java b/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java
new file mode 100644
index 0000000000..3044b8b207
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/f/FeastOfFlesh.java
@@ -0,0 +1,77 @@
+/*
+ * 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.f;
+
+import java.util.UUID;
+import mage.abilities.dynamicvalue.IntPlusDynamicValue;
+import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.DamageTargetEffect;
+import mage.abilities.effects.common.GainLifeEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.NamePredicate;
+import mage.target.common.TargetCreaturePermanent;
+
+/**
+ *
+ * @author L_J
+ */
+public class FeastOfFlesh extends CardImpl {
+
+ private static final FilterCard filter = new FilterCard("cards named Feast of Flesh");
+
+ static {
+ filter.add(new NamePredicate("Feast of Flesh"));
+ }
+
+ public FeastOfFlesh(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}");
+
+ // Feast of Flesh deals X damage to target creature and you gain X life, where X is 1 plus the number of cards named Feast of Flesh in all graveyards.
+ IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
+ Effect effect1 = new DamageTargetEffect(value);
+ effect1.setText("Feast of Flesh deals X damage to target creature");
+ Effect effect2 = new GainLifeEffect(value);
+ effect2.setText("and you gain X life, where X is 1 plus the number of cards named {source} in all graveyards");
+ this.getSpellAbility().addEffect(effect1);
+ this.getSpellAbility().addEffect(effect2);
+ this.getSpellAbility().addTarget(new TargetCreaturePermanent());
+ }
+
+ public FeastOfFlesh(final FeastOfFlesh card) {
+ super(card);
+ }
+
+ @Override
+ public FeastOfFlesh copy() {
+ return new FeastOfFlesh(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java b/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java
index e2e32e699b..71ec564a9a 100644
--- a/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java
+++ b/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java
@@ -27,10 +27,9 @@
*/
package mage.cards.f;
+import java.util.UUID;
import mage.MageInt;
-import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect;
import mage.abilities.keyword.CrewAbility;
import mage.abilities.keyword.HasteAbility;
@@ -41,8 +40,6 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
-import java.util.UUID;
-
/**
*
* @author emerald000
@@ -50,7 +47,7 @@ import java.util.UUID;
public class FleetwheelCruiser extends CardImpl {
public FleetwheelCruiser(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(5);
this.toughness = new MageInt(3);
@@ -62,13 +59,8 @@ public class FleetwheelCruiser extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// When Fleetwheel Cruiser enters the battlefield, it becomes an artifact creature until the end of turn.
- Effect effect = new AddCardTypeSourceEffect(CardType.ARTIFACT, Duration.EndOfTurn);
- effect.setText("it becomes an artifact");
- Ability ability = new EntersBattlefieldTriggeredAbility(effect);
- effect = new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn);
- effect.setText(" creature until end of turn");
- ability.addEffect(effect);
- this.addAbility(ability);
+ this.addAbility(new EntersBattlefieldTriggeredAbility(
+ new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE)));
// Crew 2
this.addAbility(new CrewAbility(2));
diff --git a/Mage.Sets/src/mage/cards/f/FrostwebSpider.java b/Mage.Sets/src/mage/cards/f/FrostwebSpider.java
new file mode 100644
index 0000000000..7fe12014a9
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/f/FrostwebSpider.java
@@ -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.f;
+
+import java.util.UUID;
+import mage.MageInt;
+import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
+import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.keyword.ReachAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.SuperType;
+import mage.counters.CounterType;
+import mage.constants.Zone;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AbilityPredicate;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+/**
+ *
+ * @author L_J
+ */
+public class FrostwebSpider extends CardImpl {
+
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying");
+
+ static {
+ filter.add(new AbilityPredicate(FlyingAbility.class));
+ }
+
+ public FrostwebSpider(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
+ this.addSuperType(SuperType.SNOW);
+ this.subtype.add(SubType.SPIDER);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(3);
+
+ // Reach
+ this.addAbility(ReachAbility.getInstance());
+
+ // Whenever Frostweb Spider blocks a creature with flying, put a +1/+1 counter on Frostweb Spider at end of combat.
+ Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())), true);
+ effect.setText("put a +1/+1 counter on {this} at end of combat");
+ this.addAbility(new FrostwebSpiderTriggeredAbility(effect, filter, false));
+ }
+
+ public FrostwebSpider(final FrostwebSpider card) {
+ super(card);
+ }
+
+ @Override
+ public FrostwebSpider copy() {
+ return new FrostwebSpider(this);
+ }
+}
+
+class FrostwebSpiderTriggeredAbility extends TriggeredAbilityImpl {
+
+ protected FilterPermanent filter;
+
+ public FrostwebSpiderTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
+ super(Zone.BATTLEFIELD, effect, optional);
+ this.filter = filter;
+ }
+
+ public FrostwebSpiderTriggeredAbility(final FrostwebSpiderTriggeredAbility ability) {
+ super(ability);
+ this.filter = ability.filter;
+ }
+
+ @Override
+ public boolean checkEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
+ }
+
+ @Override
+ public boolean checkTrigger(GameEvent event, Game game) {
+ if (event.getSourceId().equals(this.getSourceId())) {
+ Permanent blocked = game.getPermanent(event.getTargetId());
+ if (blocked != null && filter.match(blocked, game)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String getRule() {
+ return "Whenever {this} blocks a " + filter.getMessage() + ", " + super.getRule();
+ }
+
+ @Override
+ public FrostwebSpiderTriggeredAbility copy() {
+ return new FrostwebSpiderTriggeredAbility(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/g/GarbageElemental.java b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java
similarity index 92%
rename from Mage.Sets/src/mage/cards/g/GarbageElemental.java
rename to Mage.Sets/src/mage/cards/g/GarbageElementalC.java
index dcbe7c4a4c..98787e370e 100644
--- a/Mage.Sets/src/mage/cards/g/GarbageElemental.java
+++ b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java
@@ -37,6 +37,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
+import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.CounterPredicate;
import mage.game.Game;
@@ -48,12 +49,12 @@ import mage.players.Player;
*
* @author spjspj
*/
-public class GarbageElemental extends CardImpl {
+public class GarbageElementalC extends CardImpl {
- public GarbageElemental(UUID ownerId, CardSetInfo setInfo) {
+ public GarbageElementalC(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}");
- this.subtype.add("Elemental");
+ this.subtype.add(SubType.ELEMENTAL);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
@@ -68,13 +69,13 @@ public class GarbageElemental extends CardImpl {
}
- public GarbageElemental(final GarbageElemental card) {
+ public GarbageElementalC(final GarbageElementalC card) {
super(card);
}
@Override
- public GarbageElemental copy() {
- return new GarbageElemental(this);
+ public GarbageElementalC copy() {
+ return new GarbageElementalC(this);
}
}
@@ -106,7 +107,7 @@ class GarbageElementalEffect extends OneShotEffect {
if (controller != null) {
int thisRoll = controller.rollDice(game, 6);
int thatRoll = controller.rollDice(game, 6);
-
+
Token token = new GoblinToken();
return token.putOntoBattlefield(Math.abs(thatRoll - thisRoll), game, source.getSourceId(), source.getControllerId());
}
diff --git a/Mage.Sets/src/mage/cards/g/GarzasAssassin.java b/Mage.Sets/src/mage/cards/g/GarzasAssassin.java
new file mode 100644
index 0000000000..4b11642678
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/g/GarzasAssassin.java
@@ -0,0 +1,126 @@
+/*
+ * 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.ObjectColor;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.Cost;
+import mage.abilities.costs.CostImpl;
+import mage.abilities.costs.common.SacrificeSourceCost;
+import mage.abilities.effects.common.DestroyTargetEffect;
+import mage.abilities.keyword.RecoverAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.ColorPredicate;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.common.TargetCreaturePermanent;
+
+/**
+ *
+ * @author choiseul11 & L_J
+ */
+public class GarzasAssassin extends CardImpl {
+
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creature");
+
+ static {
+ filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
+ }
+
+ public GarzasAssassin(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}{B}");
+ this.subtype.add(SubType.HUMAN);
+ this.subtype.add(SubType.ASSASSIN);
+ this.power = new MageInt(2);
+ this.toughness = new MageInt(2);
+
+ // Sacrifice Garza's Assassin: Destroy target nonblack creature.
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new SacrificeSourceCost());
+ ability.addTarget(new TargetCreaturePermanent(filter));
+ this.addAbility(ability);
+
+ // Recover—Pay half your life, rounded up.
+ this.addAbility(new RecoverAbility(new GarzasAssassinCost(), this));
+ }
+
+ public GarzasAssassin(final GarzasAssassin card) {
+ super(card);
+ }
+
+ @Override
+ public GarzasAssassin copy() {
+ return new GarzasAssassin(this);
+ }
+}
+
+class GarzasAssassinCost extends CostImpl {
+
+ GarzasAssassinCost() {
+ this.text = "Pay half your life, rounded up";
+ }
+
+ GarzasAssassinCost(GarzasAssassinCost cost) {
+ super(cost);
+ }
+
+ @Override
+ public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
+ Player controller = game.getPlayer(controllerId);
+ return controller != null && (controller.getLife() < 1 || controller.canPayLifeCost());
+ }
+
+ @Override
+ public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
+ Player controller = game.getPlayer(controllerId);
+ if (controller != null) {
+ int currentLife = controller.getLife();
+ int lifeToPay = (currentLife + currentLife % 2) / 2; // Divide by two and round up.
+ if (lifeToPay < 0) {
+ this.paid = true;
+ } else {
+ this.paid = (controller.loseLife(lifeToPay, game, false) == lifeToPay);
+ }
+ return this.paid;
+ }
+ return false;
+ }
+
+ @Override
+ public GarzasAssassinCost copy() {
+ return new GarzasAssassinCost(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/g/GoblinFurrier.java b/Mage.Sets/src/mage/cards/g/GoblinFurrier.java
new file mode 100644
index 0000000000..d54976d597
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/g/GoblinFurrier.java
@@ -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.SimpleStaticAbility;
+import mage.abilities.effects.PreventionEffectImpl;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Duration;
+import mage.constants.Zone;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+
+/**
+ *
+ * @author LevelX2 & L_J
+ */
+public class GoblinFurrier extends CardImpl {
+
+ public GoblinFurrier(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}");
+ this.subtype.add(SubType.GOBLIN);
+ this.subtype.add(SubType.WARRIOR);
+ this.power = new MageInt(2);
+ this.toughness = new MageInt(2);
+
+ // Prevent all damage that Goblin Furrier would deal to snow creatures.
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GoblinFurrierPreventEffectEffect(Duration.WhileOnBattlefield)));
+ }
+
+ public GoblinFurrier(final GoblinFurrier card) {
+ super(card);
+ }
+
+ @Override
+ public GoblinFurrier copy() {
+ return new GoblinFurrier(this);
+ }
+}
+
+class GoblinFurrierPreventEffectEffect extends PreventionEffectImpl {
+
+ public GoblinFurrierPreventEffectEffect(Duration duration) {
+ super(duration, Integer.MAX_VALUE, false);
+ staticText = "Prevent all damage that {this} would deal to snow creatures";
+ }
+
+ public GoblinFurrierPreventEffectEffect(final GoblinFurrierPreventEffectEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public GoblinFurrierPreventEffectEffect copy() {
+ return new GoblinFurrierPreventEffectEffect(this);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ if (super.applies(event, source, game)) {
+ if (event.getSourceId().equals(source.getSourceId())) {
+ Permanent damageTo = game.getPermanent(event.getTargetId());
+ return damageTo != null && damageTo.isSnow();
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/Mage.Sets/src/mage/cards/h/HeartOfKiran.java b/Mage.Sets/src/mage/cards/h/HeartOfKiran.java
index 6ef4ab322a..728776ed32 100644
--- a/Mage.Sets/src/mage/cards/h/HeartOfKiran.java
+++ b/Mage.Sets/src/mage/cards/h/HeartOfKiran.java
@@ -27,6 +27,7 @@
*/
package mage.cards.h;
+import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@@ -48,8 +49,6 @@ import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetControlledPermanent;
-import java.util.UUID;
-
/**
* @author JRHerlehy
*/
@@ -74,7 +73,7 @@ public class HeartOfKiran extends CardImpl {
// You may remove a loyalty counter from a planeswalker you control rather than pay Heart of Kiran's crew cost.
Cost cost = new HeartOfKiranAlternateCrewCost(CounterType.LOYALTY, 1);
- Effect effect = new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn);
+ Effect effect = new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.CREATURE, CardType.CREATURE);
effect.setText("You may remove a loyalty counter from a planeswalker you control rather than pay {this}'s crew cost");
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, cost));
}
@@ -91,8 +90,8 @@ public class HeartOfKiran extends CardImpl {
class HeartOfKiranAlternateCrewCost extends CostImpl {
- private CounterType counterTypeToRemove;
- private int countersToRemove;
+ private final CounterType counterTypeToRemove;
+ private final int countersToRemove;
private static final FilterControlledPlaneswalkerPermanent filter = new FilterControlledPlaneswalkerPermanent("planeswalker you control");
diff --git a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java
index f5e49c19bb..f4524a00fa 100644
--- a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java
+++ b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java
@@ -27,7 +27,6 @@
*/
package mage.cards.h;
-import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
@@ -35,12 +34,8 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect;
-import mage.abilities.effects.common.cost.SpellsCostReductionAllOfChosenSubtypeEffect;
-import mage.cards.Card;
-import mage.cards.CardImpl;
-import mage.cards.CardSetInfo;
-import mage.cards.Cards;
-import mage.cards.CardsImpl;
+import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
+import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
@@ -50,6 +45,8 @@ import mage.filter.predicate.mageobject.ChosenSubtypePredicate;
import mage.game.Game;
import mage.players.Player;
+import java.util.UUID;
+
/**
*
* @author Saga
@@ -64,7 +61,7 @@ public class HeraldsHorn extends CardImpl {
// Creature spells you cast of the chosen type cost {1} less to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
- new SpellsCostReductionAllOfChosenSubtypeEffect(new FilterCreatureCard("Creature spells you cast of the chosen type"), 1)));
+ new SpellsCostReductionControllerEffect(new FilterCreatureCard("Creature spells you cast of the chosen type"), 1)));
// At the beginning of your upkeep, look at the top card of your library. If it's a creature card of the chosen type, you may reveal it and put it into your hand.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new HeraldsHornEffect(), TargetController.YOU, false));
diff --git a/Mage.Sets/src/mage/cards/h/Heroism.java b/Mage.Sets/src/mage/cards/h/Heroism.java
index 34ac472c95..cb1c9ef02b 100644
--- a/Mage.Sets/src/mage/cards/h/Heroism.java
+++ b/Mage.Sets/src/mage/cards/h/Heroism.java
@@ -112,6 +112,7 @@ class HeroismEffect extends OneShotEffect {
Cost cost = new ManaCostsImpl("{2}{R}");
List permanentsToPrevent = new ArrayList<>();
for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) {
+ cost.clearPaid();
String message = "Pay " + cost.getText() + "? If you don't, " + permanent.getLogName() + "'s combat damage will be prevented this turn.";
if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) {
if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) {
diff --git a/Mage.Sets/src/mage/cards/k/KarnsTouch.java b/Mage.Sets/src/mage/cards/k/KarnsTouch.java
index 1d108e1261..40801e90f5 100644
--- a/Mage.Sets/src/mage/cards/k/KarnsTouch.java
+++ b/Mage.Sets/src/mage/cards/k/KarnsTouch.java
@@ -99,6 +99,9 @@ class KarnsTouchEffect extends ContinuousEffectImpl {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
+ if (!artifact.isArtifact()) {
+ artifact.addCardType(CardType.ARTIFACT);
+ }
if (!artifact.isCreature()) {
artifact.addCardType(CardType.CREATURE);
}
diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java b/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java
new file mode 100644
index 0000000000..f7d5617f27
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/k/KjeldoranWarCry.java
@@ -0,0 +1,73 @@
+/*
+ * 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.k;
+
+import java.util.UUID;
+import mage.abilities.dynamicvalue.IntPlusDynamicValue;
+import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.continuous.BoostControlledEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.filter.FilterCard;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.NamePredicate;
+
+/**
+ *
+ * @author L_J
+ */
+public class KjeldoranWarCry extends CardImpl {
+
+ private static final FilterCard filter = new FilterCard("cards named Kjeldoran War Cry");
+
+ static {
+ filter.add(new NamePredicate("Kjeldoran War Cry"));
+ }
+
+ public KjeldoranWarCry(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
+
+ // Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named Kjeldoran War Cry in all graveyards.
+ IntPlusDynamicValue value = new IntPlusDynamicValue(1, new CardsInAllGraveyardsCount(filter));
+ Effect effect = new BoostControlledEffect(value, value, Duration.EndOfTurn, new FilterCreaturePermanent("creatures"), false, true);
+ effect.setText("Creatures you control get +X/+X until end of turn, where X is 1 plus the number of cards named {source} in all graveyards");
+ this.getSpellAbility().addEffect(effect);
+ }
+
+ public KjeldoranWarCry(final KjeldoranWarCry card) {
+ super(card);
+ }
+
+ @Override
+ public KjeldoranWarCry copy() {
+ return new KjeldoranWarCry(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/l/LiquimetalCoating.java b/Mage.Sets/src/mage/cards/l/LiquimetalCoating.java
index 6883d4f7d3..844e2c7cf0 100644
--- a/Mage.Sets/src/mage/cards/l/LiquimetalCoating.java
+++ b/Mage.Sets/src/mage/cards/l/LiquimetalCoating.java
@@ -50,7 +50,7 @@ public class LiquimetalCoating extends CardImpl {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
// {T}: Target permanent becomes an artifact in addition to its other types until end of turn.
- Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn), new TapSourceCost());
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT), new TapSourceCost());
ability.addTarget(new TargetPermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/m/Memnarch.java b/Mage.Sets/src/mage/cards/m/Memnarch.java
index 1d4e583c06..504671d340 100644
--- a/Mage.Sets/src/mage/cards/m/Memnarch.java
+++ b/Mage.Sets/src/mage/cards/m/Memnarch.java
@@ -60,7 +60,7 @@ public class Memnarch extends CardImpl {
this.toughness = new MageInt(5);
// {1}{U}{U}: Target permanent becomes an artifact in addition to its other types.
- Effect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield);
+ Effect effect = new AddCardTypeTargetEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT);
effect.setText("Target permanent becomes an artifact in addition to its other types");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{U}{U}"));
ability.addTarget(new TargetPermanent());
diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java
index 2481c41ee8..ca3972d399 100644
--- a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java
+++ b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java
@@ -103,7 +103,7 @@ class MirrorOfTheForebearsCopyEffect extends OneShotEffect {
if (sourcePermanent != null && copyFromPermanent != null) {
game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent());
if (!copyFromPermanent.isArtifact()) {
- ContinuousEffect effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn);
+ ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT);
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);
}
diff --git a/Mage.Sets/src/mage/cards/m/MyrLandshaper.java b/Mage.Sets/src/mage/cards/m/MyrLandshaper.java
index ce9b56dad4..09eff4a622 100644
--- a/Mage.Sets/src/mage/cards/m/MyrLandshaper.java
+++ b/Mage.Sets/src/mage/cards/m/MyrLandshaper.java
@@ -55,7 +55,7 @@ public class MyrLandshaper extends CardImpl {
this.toughness = new MageInt(1);
// {tap}: Target land becomes an artifact in addition to its other types until end of turn.
- Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn), new TapSourceCost());
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT), new TapSourceCost());
Target target = new TargetLandPermanent();
ability.addTarget(target);
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java b/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java
index 2026de28a9..0f8ac6c009 100644
--- a/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java
+++ b/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java
@@ -67,7 +67,7 @@ public class PeacewalkerColossus extends CardImpl {
this.toughness = new MageInt(6);
// {1}{W}: Another target Vehicle you control becomes an artifact creature until end of turn.
- Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfTurn);
+ Effect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.CREATURE);
effect.setText("Another target Vehicle you control becomes an artifact creature until end of turn");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{W}"));
ability.addTarget(new TargetControlledPermanent(filter));
diff --git a/Mage.Sets/src/mage/cards/r/RimehornAurochs.java b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java
new file mode 100644
index 0000000000..3217cf49b9
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java
@@ -0,0 +1,153 @@
+/*
+ * 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.r;
+
+import java.util.UUID;
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.AttacksTriggeredAbility;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.mana.ManaCostsImpl;
+import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
+import mage.abilities.dynamicvalue.common.StaticValue;
+import mage.abilities.effects.RequirementEffect;
+import mage.abilities.effects.common.continuous.BoostSourceEffect;
+import mage.abilities.keyword.TrampleAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.permanent.AnotherPredicate;
+import mage.filter.predicate.permanent.AttackingPredicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.target.common.TargetCreaturePermanent;
+import mage.watchers.common.BlockedAttackerWatcher;
+
+/**
+ *
+ * @author jeffwadsworth & L_J
+ */
+public class RimehornAurochs extends CardImpl {
+
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.AUROCHS, "other attacking Aurochs");
+
+ static {
+ filter.add(new AttackingPredicate());
+ filter.add(new AnotherPredicate());
+ }
+
+ public RimehornAurochs(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}");
+ this.addSuperType(SuperType.SNOW);
+ this.subtype.add(SubType.AUROCHS);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(3);
+
+ // Trample
+ this.addAbility(TrampleAbility.getInstance());
+
+ // Whenever Rimehorn Aurochs attacks, it gets +1/+0 until end of turn for each other attacking Aurochs.
+ this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(filter), new StaticValue(0), Duration.EndOfTurn, true), false));
+
+ // {2}{S}: Target creature blocks target creature this turn if able.
+ Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RimehornAurochsEffect(), new ManaCostsImpl("{2}{S}"));
+ ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that must block")));
+ ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature that is to be blocked")));
+ this.addAbility(ability, new BlockedAttackerWatcher());
+ }
+
+ public RimehornAurochs(final RimehornAurochs card) {
+ super(card);
+ }
+
+ @Override
+ public RimehornAurochs copy() {
+ return new RimehornAurochs(this);
+ }
+}
+
+class RimehornAurochsEffect extends RequirementEffect {
+
+ public RimehornAurochsEffect() {
+ this(Duration.EndOfTurn);
+ }
+
+ public RimehornAurochsEffect(Duration duration) {
+ super(duration);
+ staticText = "Target creature blocks target creature this turn if able";
+ }
+
+ public RimehornAurochsEffect(final RimehornAurochsEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public boolean applies(Permanent permanent, Ability source, Game game) {
+ if (permanent.getId().equals(source.getTargets().get(0).getFirstTarget())) {
+ Permanent blocker = game.getPermanent(source.getTargets().get(0).getFirstTarget());
+ if (blocker != null
+ && blocker.canBlock(source.getTargets().get(1).getFirstTarget(), game)) {
+ Permanent attacker = (Permanent) game.getPermanent(source.getTargets().get(1).getFirstTarget());
+ if (attacker != null) {
+ BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName());
+ if (blockedAttackerWatcher != null
+ && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) {
+ // has already blocked this turn, so no need to do again
+ return false;
+ }
+ return true;
+ } else {
+ discard();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean mustAttack(Game game) {
+ return false;
+ }
+
+ @Override
+ public boolean mustBlock(Game game) {
+ return true;
+ }
+
+ @Override
+ public UUID mustBlockAttacker(Ability source, Game game) {
+ return source.getTargets().get(1).getFirstTarget();
+ }
+
+ @Override
+ public RimehornAurochsEffect copy() {
+ return new RimehornAurochsEffect(this);
+ }
+
+}
diff --git a/Mage.Sets/src/mage/cards/s/ShiningShoal.java b/Mage.Sets/src/mage/cards/s/ShiningShoal.java
index f7d2a1c6c3..84dc870b36 100644
--- a/Mage.Sets/src/mage/cards/s/ShiningShoal.java
+++ b/Mage.Sets/src/mage/cards/s/ShiningShoal.java
@@ -27,6 +27,7 @@
*/
package mage.cards.s;
+import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
@@ -34,7 +35,7 @@ import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.common.ExileFromHandCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.ExileFromHandCostCardConvertedMana;
-import mage.abilities.effects.PreventionEffectImpl;
+import mage.abilities.effects.common.RedirectDamageFromSourceToTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -45,7 +46,6 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
-import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
@@ -53,8 +53,6 @@ import mage.target.TargetSource;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCreatureOrPlayer;
-import java.util.UUID;
-
/**
*
* @author LevelX2
@@ -62,7 +60,7 @@ import java.util.UUID;
public class ShiningShoal extends CardImpl {
public ShiningShoal(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}");
this.subtype.add(SubType.ARCANE);
// You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost
@@ -72,7 +70,7 @@ public class ShiningShoal extends CardImpl {
this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true)));
// The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead.
- this.getSpellAbility().addEffect(new ShiningShoalPreventDamageTargetEffect(Duration.EndOfTurn, new ExileFromHandCostCardConvertedMana()));
+ this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect(Duration.EndOfTurn, new ExileFromHandCostCardConvertedMana()));
this.getSpellAbility().addTarget(new TargetSource());
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
}
@@ -87,31 +85,29 @@ public class ShiningShoal extends CardImpl {
}
}
-class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
+class ShiningShoalRedirectDamageTargetEffect extends RedirectDamageFromSourceToTargetEffect {
private final DynamicValue dynamicAmount;
- private int amount;
- public ShiningShoalPreventDamageTargetEffect(Duration duration, DynamicValue dynamicAmount) {
- super(duration);
+ public ShiningShoalRedirectDamageTargetEffect(Duration duration, DynamicValue dynamicAmount) {
+ super(duration, 0, true);
this.dynamicAmount = dynamicAmount;
staticText = "The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to target creature or player instead";
}
- public ShiningShoalPreventDamageTargetEffect(final ShiningShoalPreventDamageTargetEffect effect) {
+ public ShiningShoalRedirectDamageTargetEffect(final ShiningShoalRedirectDamageTargetEffect effect) {
super(effect);
- this.amount = effect.amount;
this.dynamicAmount = effect.dynamicAmount;
}
@Override
- public ShiningShoalPreventDamageTargetEffect copy() {
- return new ShiningShoalPreventDamageTargetEffect(this);
+ public ShiningShoalRedirectDamageTargetEffect copy() {
+ return new ShiningShoalRedirectDamageTargetEffect(this);
}
@Override
public void init(Ability source, Game game) {
- this.amount = dynamicAmount.calculate(game, source, this);
+ amountToRedirect = dynamicAmount.calculate(game, source, this);
}
@Override
@@ -119,49 +115,9 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
return true;
}
- @Override
- public boolean replaceEvent(GameEvent event, Ability source, Game game) {
- GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), event.getAmount(), false);
- if (!game.replaceEvent(preventEvent)) {
- int prevented;
- if (event.getAmount() >= this.amount) {
- int damage = amount;
- event.setAmount(event.getAmount() - amount);
- this.used = true;
- game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage));
- prevented = damage;
- } else {
- int damage = event.getAmount();
- event.setAmount(0);
- amount -= damage;
- game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getFirstTarget(), source.getSourceId(), source.getControllerId(), damage));
- prevented = damage;
- }
-
- // deal damage now
- if (prevented > 0) {
- UUID redirectTo = source.getTargets().get(1).getFirstTarget();
- Permanent permanent = game.getPermanent(redirectTo);
- MageObject sourceObject = game.getObject(source.getFirstTarget());
- if (permanent != null) {
- game.informPlayers(sourceObject.getIdName() + "deals " + prevented + " to " + permanent.getName() + " instead");
- // keep the original source id as it is redirecting
- permanent.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects());
- }
- Player player = game.getPlayer(redirectTo);
- if (player != null) {
- game.informPlayers(sourceObject.getIdName() + "deals " + prevented + " to " + player.getLogName() + " instead");
- // keep the original source id as it is redirecting
- player.damage(prevented, event.getSourceId(), game, ((DamageEvent) event).isCombatDamage(), ((DamageEvent) event).isPreventable(), event.getAppliedEffects());
- }
- }
- }
- return false;
- }
-
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
- if (!this.used && super.applies(event, source, game)) {
+ if (!this.used && event.getFlag()) {
// get source of the damage event
MageObject sourceObject = game.getObject(event.getSourceId());
@@ -173,7 +129,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
return false;
}
// do the 2 objects match?
- if (sourceObject.getId() != chosenSourceObject.getId()) {
+ if (!sourceObject.getId().equals(chosenSourceObject.getId())) {
return false;
}
@@ -183,6 +139,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
if (permanent != null && permanent.isCreature()) {
if (permanent.getControllerId().equals(source.getControllerId())) {
// it's your creature
+ redirectTarget = source.getTargets().get(1);
return true;
}
}
@@ -191,6 +148,7 @@ class ShiningShoalPreventDamageTargetEffect extends PreventionEffectImpl {
if (player != null) {
if (player.getId().equals(source.getControllerId())) {
// it is you
+ redirectTarget = source.getTargets().get(1);
return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/s/SilverskinArmor.java b/Mage.Sets/src/mage/cards/s/SilverskinArmor.java
index 9dfbc072d7..ef3629a1e6 100644
--- a/Mage.Sets/src/mage/cards/s/SilverskinArmor.java
+++ b/Mage.Sets/src/mage/cards/s/SilverskinArmor.java
@@ -44,12 +44,15 @@ import mage.constants.*;
public class SilverskinArmor extends CardImpl {
public SilverskinArmor(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
this.subtype.add(SubType.EQUIPMENT);
- this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}")));
+ // Equipped creature gets +1/+1 and is an artifact in addition to its other types.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 1, Duration.WhileOnBattlefield)));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddCardTypeAttachedEffect(CardType.ARTIFACT, Duration.WhileOnBattlefield, AttachmentType.EQUIPMENT)));
+
+ // Equip {2}
+ this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}")));
}
public SilverskinArmor(final SilverskinArmor card) {
diff --git a/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java b/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java
index abb6bd3e3c..fcd691c172 100644
--- a/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java
+++ b/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java
@@ -56,6 +56,7 @@ public class SydriGalvanicGenius extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("artifact creature");
private static final FilterArtifactPermanent filterNonCreature = new FilterArtifactPermanent("noncreature artifact");
+
static {
filter.add(new CardTypePredicate(CardType.ARTIFACT));
filter.add(new CardTypePredicate(CardType.CREATURE));
@@ -63,7 +64,7 @@ public class SydriGalvanicGenius extends CardImpl {
}
public SydriGalvanicGenius(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ARTIFICER);
@@ -119,6 +120,9 @@ class SydriGalvanicGeniusEffect extends ContinuousEffectImpl {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
+ if (!artifact.isArtifact()) {
+ artifact.addCardType(CardType.ARTIFACT);
+ }
if (!artifact.isCreature()) {
artifact.addCardType(CardType.CREATURE);
}
@@ -140,7 +144,6 @@ class SydriGalvanicGeniusEffect extends ContinuousEffectImpl {
return false;
}
-
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4;
diff --git a/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java b/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java
index caf6fb786b..b4a1513874 100644
--- a/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java
+++ b/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java
@@ -31,7 +31,6 @@ import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
-import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
@@ -41,12 +40,12 @@ import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect;
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.SuperType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterControlledPermanent;
+import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.players.Player;
@@ -66,7 +65,7 @@ public class TezzeretAgentOfBolas extends CardImpl {
}
public TezzeretAgentOfBolas(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{2}{U}{B}");
+ super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.TEZZERET);
@@ -76,7 +75,7 @@ public class TezzeretAgentOfBolas extends CardImpl {
this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(5, 1, filter, true), 1));
// -1: Target artifact becomes an artifact creature with base power and toughness 5/5.
- Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfGame);
+ Effect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE);
effect.setText("Target artifact becomes an artifact creature");
LoyaltyAbility ability1 = new LoyaltyAbility(effect, -1);
effect = new SetPowerToughnessTargetEffect(5, 5, Duration.EndOfGame);
@@ -105,12 +104,6 @@ public class TezzeretAgentOfBolas extends CardImpl {
class TezzeretAgentOfBolasEffect2 extends OneShotEffect {
- final static FilterControlledPermanent filter = new FilterControlledPermanent("artifacts");
-
- static {
- filter.add(new CardTypePredicate(CardType.ARTIFACT));
- }
-
public TezzeretAgentOfBolasEffect2() {
super(Outcome.DrawCard);
staticText = "Target player loses X life and you gain X life, where X is twice the number of artifacts you control";
@@ -127,16 +120,16 @@ class TezzeretAgentOfBolasEffect2 extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- DynamicValue value = new PermanentsOnBattlefieldCount(filter);
- int count = value.calculate(game, source, this) * 2;
-
- Player player = game.getPlayer(source.getFirstTarget());
- if (player != null) {
- player.loseLife(count, game, false);
- }
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
- controller.gainLife(count, game);
+ int count = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT).calculate(game, source, this) * 2;
+ if (count > 0) {
+ Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
+ if (targetPlayer != null) {
+ targetPlayer.loseLife(count, game, false);
+ }
+ Player controller = game.getPlayer(source.getControllerId());
+ if (controller != null) {
+ controller.gainLife(count, game);
+ }
}
return true;
}
diff --git a/Mage.Sets/src/mage/cards/t/ThermalFlux.java b/Mage.Sets/src/mage/cards/t/ThermalFlux.java
new file mode 100644
index 0000000000..f4bcb7c833
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/t/ThermalFlux.java
@@ -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.t;
+
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.Mode;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
+import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
+import mage.abilities.effects.common.DrawCardSourceControllerEffect;
+import mage.constants.SuperType;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.Layer;
+import mage.constants.Outcome;
+import mage.constants.SubLayer;
+import mage.filter.FilterPermanent;
+import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.SupertypePredicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.target.TargetPermanent;
+
+/**
+ *
+ * @author TheElk801 & L_J
+ */
+public class ThermalFlux extends CardImpl {
+
+ private static final FilterPermanent filterNonsnow = new FilterPermanent("nonsnow permanent");
+ private static final FilterPermanent filterSnow = new FilterPermanent("snow permanent");
+
+ static {
+ filterNonsnow.add(Predicates.not(new SupertypePredicate(SuperType.SNOW)));
+ filterSnow.add(new SupertypePredicate(SuperType.SNOW));
+ }
+
+ public ThermalFlux(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}");
+
+ // Choose one -
+ // Target nonsnow permanent becomes snow until end of turn.
+ // Draw a card at the beginning of the next turn's upkeep.
+ this.getSpellAbility().addTarget(new TargetPermanent(filterNonsnow));
+ this.getSpellAbility().addEffect(new ThermalFluxEffect(true));
+ this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(
+ new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
+ // Target snow permanent isn't snow until end of turn.
+ // Draw a card at the beginning of the next turn's upkeep.
+ Mode mode = new Mode();
+ mode.getTargets().add(new TargetPermanent(filterSnow));
+ mode.getEffects().add(new ThermalFluxEffect(false));
+ mode.getEffects().add(new CreateDelayedTriggeredAbilityEffect(
+ new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false));
+ this.getSpellAbility().addMode(mode);
+
+ }
+
+ public ThermalFlux(final ThermalFlux card) {
+ super(card);
+ }
+
+ @Override
+ public ThermalFlux copy() {
+ return new ThermalFlux(this);
+ }
+}
+
+class ThermalFluxEffect extends ContinuousEffectImpl {
+
+ private final boolean addSnow;
+
+ public ThermalFluxEffect(boolean addSnow) {
+ super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment);
+ this.addSnow = addSnow;
+ this.staticText = "Target " + (addSnow ? "non" : "") + "snow permanent " + (addSnow ? "becomes" : "isn't") + " snow until end of turn";
+ }
+
+ public ThermalFluxEffect(final ThermalFluxEffect effect) {
+ super(effect);
+ this.addSnow = effect.addSnow;
+ }
+
+ @Override
+ public ThermalFluxEffect copy() {
+ return new ThermalFluxEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Permanent permanent = game.getPermanent(source.getFirstTarget());
+ if (permanent != null) {
+ if (addSnow) {
+ permanent.addSuperType(SuperType.SNOW);
+ } else {
+ permanent.getSuperType().remove(SuperType.SNOW);
+ }
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/t/ThranForge.java b/Mage.Sets/src/mage/cards/t/ThranForge.java
index b3a9c66ed1..3d9a2e6887 100644
--- a/Mage.Sets/src/mage/cards/t/ThranForge.java
+++ b/Mage.Sets/src/mage/cards/t/ThranForge.java
@@ -65,7 +65,7 @@ public class ThranForge extends CardImpl {
.setText("Until end of turn, target nonartifact creature gets +1/+0"),
new GenericManaCost(2));
ability.addEffect(
- new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.EndOfTurn)
+ new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT)
.setText("and becomes an artifact in addition to its other types")
);
ability.addTarget(new TargetPermanent(filter));
diff --git a/Mage.Sets/src/mage/cards/t/TitaniasSong.java b/Mage.Sets/src/mage/cards/t/TitaniasSong.java
index a4a0485580..8856103e82 100644
--- a/Mage.Sets/src/mage/cards/t/TitaniasSong.java
+++ b/Mage.Sets/src/mage/cards/t/TitaniasSong.java
@@ -55,11 +55,11 @@ import mage.game.permanent.Permanent;
public class TitaniasSong extends CardImpl {
public TitaniasSong(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}");
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}");
// Each noncreature artifact loses all abilities and becomes an artifact creature with power and toughness each equal to its converted mana cost. If Titania's Song leaves the battlefield, this effect continues until end of turn.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TitaniasSongEffect(Duration.WhileOnBattlefield)));
- this.addAbility(new LeavesBattlefieldTriggeredAbility(new TitaniasSongEffect(Duration.EndOfTurn), false));
+ this.addAbility(new LeavesBattlefieldTriggeredAbility(new TitaniasSongEffect(Duration.EndOfTurn), false));
}
public TitaniasSong(final TitaniasSong card) {
@@ -71,12 +71,15 @@ public class TitaniasSong extends CardImpl {
return new TitaniasSong(this);
}
}
+
class TitaniasSongEffect extends ContinuousEffectImpl {
private static final FilterArtifactPermanent filter = new FilterArtifactPermanent();
+
static {
filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
}
+
public TitaniasSongEffect(Duration duration) {
super(duration, Outcome.BecomeCreature);
staticText = "Each noncreature artifact loses its abilities and is an artifact creature with power and toughness each equal to its converted mana cost";
@@ -97,8 +100,8 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
affectedObjectList.clear();
- for(Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)){
- if(permanent != null){
+ for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, game)) {
+ if (permanent != null) {
affectedObjectList.add(new MageObjectReference(permanent, game));
permanent.addCardType(CardType.CREATURE);
}
@@ -106,18 +109,18 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
}
break;
case AbilityAddingRemovingEffects_6:
- for (Iterator it = affectedObjectList.iterator(); it.hasNext();) {
- Permanent permanent = it.next().getPermanent(game);
- if (permanent != null){
- permanent.removeAllAbilities(source.getSourceId(), game);
- }
+ for (Iterator it = affectedObjectList.iterator(); it.hasNext();) {
+ Permanent permanent = it.next().getPermanent(game);
+ if (permanent != null) {
+ permanent.removeAllAbilities(source.getSourceId(), game);
}
- break;
+ }
+ break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
for (Iterator it = affectedObjectList.iterator(); it.hasNext();) {
Permanent permanent = it.next().getPermanent(game);
- if (permanent != null){
+ if (permanent != null) {
int manaCost = permanent.getConvertedManaCost();
permanent.getPower().setValue(manaCost);
permanent.getToughness().setValue(manaCost);
@@ -133,7 +136,6 @@ class TitaniasSongEffect extends ContinuousEffectImpl {
return false;
}
-
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4;
diff --git a/Mage.Sets/src/mage/cards/t/Toymaker.java b/Mage.Sets/src/mage/cards/t/Toymaker.java
index 19e1b67358..dd3cfa42e0 100644
--- a/Mage.Sets/src/mage/cards/t/Toymaker.java
+++ b/Mage.Sets/src/mage/cards/t/Toymaker.java
@@ -35,7 +35,6 @@ import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
-import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -43,6 +42,7 @@ import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
+import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterArtifactPermanent;
import mage.filter.predicate.Predicates;
@@ -113,6 +113,9 @@ class ToymakerEffect extends ContinuousEffectImpl {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
+ if (!artifact.isArtifact()) {
+ artifact.addCardType(CardType.ARTIFACT);
+ }
if (!artifact.isCreature()) {
artifact.addCardType(CardType.CREATURE);
}
diff --git a/Mage.Sets/src/mage/cards/t/TresserhornSkyknight.java b/Mage.Sets/src/mage/cards/t/TresserhornSkyknight.java
new file mode 100644
index 0000000000..a0e4f854ca
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/t/TresserhornSkyknight.java
@@ -0,0 +1,115 @@
+/*
+ * 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.t;
+
+import java.util.UUID;
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.effects.PreventionEffectImpl;
+import mage.abilities.keyword.FirstStrikeAbility;
+import mage.abilities.keyword.FlyingAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.constants.Zone;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.AbilityPredicate;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.DamageCreatureEvent;
+import mage.game.permanent.Permanent;
+
+/**
+ *
+ * @author L_J
+ */
+public class TresserhornSkyknight extends CardImpl {
+
+ public TresserhornSkyknight(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
+ this.subtype.add(SubType.ZOMBIE);
+ this.subtype.add(SubType.KNIGHT);
+ this.power = new MageInt(5);
+ this.toughness = new MageInt(3);
+
+ // Flying
+ this.addAbility(FlyingAbility.getInstance());
+
+ // Prevent all damage that would be dealt to Tresserhorn Skyknight by creatures with first strike.
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TresserhornSkyknightEffect()));
+ }
+
+ public TresserhornSkyknight(final TresserhornSkyknight card) {
+ super(card);
+ }
+
+ @Override
+ public TresserhornSkyknight copy() {
+ return new TresserhornSkyknight(this);
+ }
+}
+
+class TresserhornSkyknightEffect extends PreventionEffectImpl {
+
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with first strike");
+
+ static {
+ filter.add(new AbilityPredicate(FirstStrikeAbility.class));
+ }
+
+ TresserhornSkyknightEffect() {
+ super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false);
+ staticText = "Prevent all damage that would be dealt to Tresserhorn Skyknight by creatures with first strike";
+ }
+
+ TresserhornSkyknightEffect(final TresserhornSkyknightEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public TresserhornSkyknightEffect copy() {
+ return new TresserhornSkyknightEffect(this);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ if (super.applies(event, source, game) && event instanceof DamageCreatureEvent && event.getAmount() > 0) {
+ DamageCreatureEvent damageEvent = (DamageCreatureEvent) event;
+ if (event.getTargetId().equals(source.getSourceId())) {
+ Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId());
+ if (permanent != null && filter.match(permanent, game)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/v/VeryCrypticCommand.java b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java
similarity index 95%
rename from Mage.Sets/src/mage/cards/v/VeryCrypticCommand.java
rename to Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java
index d922d4f7a4..68aabe40d1 100644
--- a/Mage.Sets/src/mage/cards/v/VeryCrypticCommand.java
+++ b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java
@@ -59,7 +59,7 @@ import mage.target.common.TargetCreaturePermanent;
*
* @author spjspj
*/
-public class VeryCrypticCommand extends CardImpl {
+public class VeryCrypticCommandD extends CardImpl {
private static final FilterStackObject filter = new FilterStackObject("spell or ability with a single target");
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("nontoken creature");
@@ -69,7 +69,7 @@ public class VeryCrypticCommand extends CardImpl {
filter2.add(Predicates.not(new TokenPredicate()));
}
- public VeryCrypticCommand(UUID ownerId, CardSetInfo setInfo) {
+ public VeryCrypticCommandD(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}{U}");
// Choose two -
@@ -101,13 +101,13 @@ public class VeryCrypticCommand extends CardImpl {
this.getSpellAbility().getModes().addMode(mode);
}
- public VeryCrypticCommand(final VeryCrypticCommand card) {
+ public VeryCrypticCommandD(final VeryCrypticCommandD card) {
super(card);
}
@Override
- public VeryCrypticCommand copy() {
- return new VeryCrypticCommand(this);
+ public VeryCrypticCommandD copy() {
+ return new VeryCrypticCommandD(this);
}
}
diff --git a/Mage.Sets/src/mage/cards/v/VoidMaw.java b/Mage.Sets/src/mage/cards/v/VoidMaw.java
new file mode 100644
index 0000000000..a2e4aa8892
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/v/VoidMaw.java
@@ -0,0 +1,190 @@
+/*
+ * 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.v;
+
+import java.util.UUID;
+import mage.MageInt;
+import mage.MageObject;
+import mage.abilities.Ability;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.costs.Cost;
+import mage.abilities.costs.CostImpl;
+import mage.abilities.effects.ReplacementEffectImpl;
+import mage.abilities.effects.common.continuous.BoostSourceEffect;
+import mage.abilities.keyword.TrampleAbility;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.cards.Cards;
+import mage.constants.*;
+import mage.filter.FilterCard;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.events.ZoneChangeEvent;
+import mage.game.permanent.Permanent;
+import mage.players.Player;
+import mage.target.common.TargetCardInExile;
+import mage.util.CardUtil;
+
+/**
+ * @author jeffwadsworth & L_J
+ */
+public class VoidMaw extends CardImpl {
+
+ public VoidMaw(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
+ this.subtype.add(SubType.HORROR);
+ this.power = new MageInt(4);
+ this.toughness = new MageInt(5);
+
+ // Trample
+ this.addAbility(TrampleAbility.getInstance());
+
+ // If another creature would die, exile it instead.
+ this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VoidMawEffect()));
+
+ // Put a card exiled with Void Maw into its owner's graveyard: Void Maw gets +2/+2 until end of turn.
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new VoidMawCost()));
+ }
+
+ public VoidMaw(final VoidMaw card) {
+ super(card);
+ }
+
+ @Override
+ public VoidMaw copy() {
+ return new VoidMaw(this);
+ }
+}
+
+class VoidMawEffect extends ReplacementEffectImpl {
+
+ public VoidMawEffect() {
+ super(Duration.WhileOnBattlefield, Outcome.Benefit);
+ staticText = "If another creature would die, exile it instead";
+ }
+
+ public VoidMawEffect(final VoidMawEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public VoidMawEffect copy() {
+ return new VoidMawEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ return true;
+ }
+
+ @Override
+ public boolean replaceEvent(GameEvent event, Ability source, Game game) {
+ Player controller = game.getPlayer(source.getControllerId());
+ MageObject sourceObject = source.getSourceObject(game);
+ if (controller != null && sourceObject != null) {
+ if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
+ Permanent permanent = ((ZoneChangeEvent) event).getTarget();
+ if (permanent != null) {
+ UUID exileZoneId = CardUtil.getCardExileZoneId(game, source);
+ if (controller.moveCardsToExile(permanent, source, game, false, exileZoneId, sourceObject.getIdName())) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean checksEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.ZONE_CHANGE;
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
+ if (zEvent.getToZone() == Zone.GRAVEYARD) {
+ Permanent permanent = ((ZoneChangeEvent) event).getTarget();
+ if (permanent != null && permanent.getId() != source.getSourceId()) {
+ if (zEvent.getTarget() != null) { // if it comes from permanent, check if it was a creature on the battlefield
+ if (zEvent.getTarget().isCreature()) {
+ return true;
+ }
+ } else if (permanent.isCreature()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
+
+class VoidMawCost extends CostImpl {
+
+ public VoidMawCost() {
+ this.text = "Put a card exiled with {this} into its owner's graveyard";
+ }
+
+ public VoidMawCost(VoidMawCost cost) {
+ super(cost);
+ }
+
+ @Override
+ public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
+ Player controller = game.getPlayer(controllerId);
+ if (controller != null) {
+ TargetCardInExile target = new TargetCardInExile(new FilterCard(), CardUtil.getCardExileZoneId(game, ability));
+ target.setNotTarget(true);
+ Cards cards = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, ability));
+ if (!cards.isEmpty()
+ && controller.choose(Outcome.Benefit, cards, target, game)) {
+ Card card = game.getCard(target.getFirstTarget());
+ if (card != null) {
+ if (controller.moveCardToGraveyardWithInfo(card, sourceId, game, Zone.EXILED)) {
+ paid = true;
+ }
+ }
+ }
+ }
+ return paid;
+ }
+
+ @Override
+ public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
+ Player player = game.getPlayer(controllerId);
+ return player != null;
+ }
+
+ @Override
+ public VoidMawCost copy() {
+ return new VoidMawCost(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/x/XathridGorgon.java b/Mage.Sets/src/mage/cards/x/XathridGorgon.java
index df29417c95..87979a6662 100644
--- a/Mage.Sets/src/mage/cards/x/XathridGorgon.java
+++ b/Mage.Sets/src/mage/cards/x/XathridGorgon.java
@@ -76,7 +76,7 @@ public class XathridGorgon extends CardImpl {
Effect effect = new GainAbilityTargetEffect(DefenderAbility.getInstance(), Duration.Custom);
effect.setText("It gains defender");
ability.addEffect(effect);
- effect = new AddCardTypeTargetEffect(CardType.ARTIFACT, Duration.Custom);
+ effect = new AddCardTypeTargetEffect(Duration.Custom, CardType.ARTIFACT);
effect.setText("and becomes a colorless artifact in addition to its other types");
ability.addEffect(effect);
ability.addEffect(new BecomesColorTargetEffect(new ObjectColor(), Duration.Custom, ""));
diff --git a/Mage.Sets/src/mage/cards/x/XenicPoltergeist.java b/Mage.Sets/src/mage/cards/x/XenicPoltergeist.java
index c17170e71d..74fb2c78ed 100644
--- a/Mage.Sets/src/mage/cards/x/XenicPoltergeist.java
+++ b/Mage.Sets/src/mage/cards/x/XenicPoltergeist.java
@@ -36,12 +36,12 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.SubLayer;
+import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterArtifactPermanent;
import mage.filter.predicate.Predicates;
@@ -125,7 +125,12 @@ class XenicPoltergeistEffect extends ContinuousEffectImpl {
UUID permanentId = targetPointer.getFirst(game, source);
Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId);
if (permanent != null) {
- permanent.addCardType(CardType.CREATURE);
+ if (!permanent.isArtifact()) {
+ permanent.addCardType(CardType.ARTIFACT);
+ }
+ if (!permanent.isCreature()) {
+ permanent.addCardType(CardType.CREATURE);
+ }
}
}
break;
diff --git a/Mage.Sets/src/mage/sets/Coldsnap.java b/Mage.Sets/src/mage/sets/Coldsnap.java
index 1709fb4e29..fd5daa98b1 100644
--- a/Mage.Sets/src/mage/sets/Coldsnap.java
+++ b/Mage.Sets/src/mage/sets/Coldsnap.java
@@ -61,6 +61,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Arctic Nishoba", 102, Rarity.UNCOMMON, mage.cards.a.ArcticNishoba.class));
cards.add(new SetCardInfo("Arcum Dagsson", 27, Rarity.RARE, mage.cards.a.ArcumDagsson.class));
cards.add(new SetCardInfo("Aurochs Herd", 103, Rarity.COMMON, mage.cards.a.AurochsHerd.class));
+ cards.add(new SetCardInfo("Balduvian Frostwaker", 28, Rarity.UNCOMMON, mage.cards.b.BalduvianFrostwaker.class));
cards.add(new SetCardInfo("Balduvian Rage", 76, Rarity.UNCOMMON, mage.cards.b.BalduvianRage.class));
cards.add(new SetCardInfo("Balduvian Warlord", 77, Rarity.UNCOMMON, mage.cards.b.BalduvianWarlord.class));
cards.add(new SetCardInfo("Blizzard Specter", 126, Rarity.UNCOMMON, mage.cards.b.BlizzardSpecter.class));
@@ -86,16 +87,20 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Disciple of Tevesh Szat", 55, Rarity.COMMON, mage.cards.d.DiscipleOfTeveshSzat.class));
cards.add(new SetCardInfo("Drelnoch", 32, Rarity.COMMON, mage.cards.d.Drelnoch.class));
cards.add(new SetCardInfo("Earthen Goo", 80, Rarity.UNCOMMON, mage.cards.e.EarthenGoo.class));
+ cards.add(new SetCardInfo("Feast of Flesh", 56, Rarity.COMMON, mage.cards.f.FeastOfFlesh.class));
cards.add(new SetCardInfo("Field Marshal", 5, Rarity.RARE, mage.cards.f.FieldMarshal.class));
cards.add(new SetCardInfo("Flashfreeze", 33, Rarity.UNCOMMON, mage.cards.f.Flashfreeze.class));
cards.add(new SetCardInfo("Freyalise's Radiance", 108, Rarity.UNCOMMON, mage.cards.f.FreyalisesRadiance.class));
cards.add(new SetCardInfo("Frost Marsh", 146, Rarity.UNCOMMON, mage.cards.f.FrostMarsh.class));
cards.add(new SetCardInfo("Frost Raptor", 34, Rarity.COMMON, mage.cards.f.FrostRaptor.class));
+ cards.add(new SetCardInfo("Frostweb Spider", 109, Rarity.COMMON, mage.cards.f.FrostwebSpider.class));
cards.add(new SetCardInfo("Frozen Solid", 35, Rarity.COMMON, mage.cards.f.FrozenSolid.class));
cards.add(new SetCardInfo("Fury of the Horde", 81, Rarity.RARE, mage.cards.f.FuryOfTheHorde.class));
cards.add(new SetCardInfo("Garza Zol, Plague Queen", 129, Rarity.RARE, mage.cards.g.GarzaZolPlagueQueen.class));
+ cards.add(new SetCardInfo("Garza's Assassin", 57, Rarity.RARE, mage.cards.g.GarzasAssassin.class));
cards.add(new SetCardInfo("Gelid Shackles", 6, Rarity.COMMON, mage.cards.g.GelidShackles.class));
cards.add(new SetCardInfo("Glacial Plating", 7, Rarity.UNCOMMON, mage.cards.g.GlacialPlating.class));
+ cards.add(new SetCardInfo("Goblin Furrier", 82, Rarity.COMMON, mage.cards.g.GoblinFurrier.class));
cards.add(new SetCardInfo("Goblin Rimerunner", 83, Rarity.COMMON, mage.cards.g.GoblinRimerunner.class));
cards.add(new SetCardInfo("Greater Stone Spirit", 84, Rarity.UNCOMMON, mage.cards.g.GreaterStoneSpirit.class));
cards.add(new SetCardInfo("Grim Harvest", 58, Rarity.COMMON, mage.cards.g.GrimHarvest.class));
@@ -119,6 +124,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Kjeldoran Gargoyle", 10, Rarity.UNCOMMON, mage.cards.k.KjeldoranGargoyle.class));
cards.add(new SetCardInfo("Kjeldoran Javelineer", 11, Rarity.COMMON, mage.cards.k.KjeldoranJavelineer.class));
cards.add(new SetCardInfo("Kjeldoran Outrider", 12, Rarity.COMMON, mage.cards.k.KjeldoranOutrider.class));
+ cards.add(new SetCardInfo("Kjeldoran War Cry", 13, Rarity.COMMON, mage.cards.k.KjeldoranWarCry.class));
cards.add(new SetCardInfo("Krovikan Mist", 38, Rarity.COMMON, mage.cards.k.KrovikanMist.class));
cards.add(new SetCardInfo("Krovikan Rot", 63, Rarity.UNCOMMON, mage.cards.k.KrovikanRot.class));
cards.add(new SetCardInfo("Krovikan Scoundrel", 64, Rarity.COMMON, mage.cards.k.KrovikanScoundrel.class));
@@ -150,6 +156,7 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Rimebound Dead", 69, Rarity.COMMON, mage.cards.r.RimeboundDead.class));
cards.add(new SetCardInfo("Rime Transfusion", 68, Rarity.UNCOMMON, mage.cards.r.RimeTransfusion.class));
cards.add(new SetCardInfo("Rimefeather Owl", 42, Rarity.RARE, mage.cards.r.RimefeatherOwl.class));
+ cards.add(new SetCardInfo("Rimehorn Aurochs", 118, Rarity.UNCOMMON, mage.cards.r.RimehornAurochs.class));
cards.add(new SetCardInfo("Rimescale Dragon", 95, Rarity.RARE, mage.cards.r.RimescaleDragon.class));
cards.add(new SetCardInfo("Rimewind Cryomancer", 43, Rarity.UNCOMMON, mage.cards.r.RimewindCryomancer.class));
cards.add(new SetCardInfo("Rimewind Taskmage", 44, Rarity.COMMON, mage.cards.r.RimewindTaskmage.class));
@@ -184,12 +191,15 @@ public class Coldsnap extends ExpansionSet {
cards.add(new SetCardInfo("Survivor of the Unseen", 48, Rarity.COMMON, mage.cards.s.SurvivorOfTheUnseen.class));
cards.add(new SetCardInfo("Swift Maneuver", 21, Rarity.COMMON, mage.cards.s.SwiftManeuver.class));
cards.add(new SetCardInfo("Tamanoa", 132, Rarity.RARE, mage.cards.t.Tamanoa.class));
+ cards.add(new SetCardInfo("Thermal Flux", 49, Rarity.COMMON, mage.cards.t.ThermalFlux.class));
cards.add(new SetCardInfo("Thermopod", 100, Rarity.COMMON, mage.cards.t.Thermopod.class));
cards.add(new SetCardInfo("Thrumming Stone", 142, Rarity.RARE, mage.cards.t.ThrummingStone.class));
cards.add(new SetCardInfo("Tresserhorn Sinks", 150, Rarity.UNCOMMON, mage.cards.t.TresserhornSinks.class));
+ cards.add(new SetCardInfo("Tresserhorn Skyknight", 73, Rarity.UNCOMMON, mage.cards.t.TresserhornSkyknight.class));
cards.add(new SetCardInfo("Ursine Fylgja", 22, Rarity.UNCOMMON, mage.cards.u.UrsineFylgja.class));
cards.add(new SetCardInfo("Vanish into Memory", 133, Rarity.UNCOMMON, mage.cards.v.VanishIntoMemory.class));
cards.add(new SetCardInfo("Vexing Sphinx", 50, Rarity.RARE, mage.cards.v.VexingSphinx.class));
+ cards.add(new SetCardInfo("Void Maw", 74, Rarity.RARE, mage.cards.v.VoidMaw.class));
cards.add(new SetCardInfo("Wall of Shards", 23, Rarity.UNCOMMON, mage.cards.w.WallOfShards.class));
cards.add(new SetCardInfo("White Shield Crusader", 24, Rarity.UNCOMMON, mage.cards.w.WhiteShieldCrusader.class));
cards.add(new SetCardInfo("Wilderness Elemental", 134, Rarity.UNCOMMON, mage.cards.w.WildernessElemental.class));
diff --git a/Mage.Sets/src/mage/sets/FutureSight.java b/Mage.Sets/src/mage/sets/FutureSight.java
index f3bc906701..6edb2d5ce9 100644
--- a/Mage.Sets/src/mage/sets/FutureSight.java
+++ b/Mage.Sets/src/mage/sets/FutureSight.java
@@ -94,6 +94,7 @@ public class FutureSight extends ExpansionSet {
cards.add(new SetCardInfo("Emberwilde Augur", 97, Rarity.COMMON, mage.cards.e.EmberwildeAugur.class));
cards.add(new SetCardInfo("Emblem of the Warmind", 112, Rarity.UNCOMMON, mage.cards.e.EmblemOfTheWarmind.class));
cards.add(new SetCardInfo("Epochrasite", 162, Rarity.RARE, mage.cards.e.Epochrasite.class));
+ cards.add(new SetCardInfo("Even the Odds", 6, Rarity.UNCOMMON, mage.cards.e.EvenTheOdds.class));
cards.add(new SetCardInfo("Fatal Attraction", 98, Rarity.COMMON, mage.cards.f.FatalAttraction.class));
cards.add(new SetCardInfo("Festering March", 65, Rarity.UNCOMMON, mage.cards.f.FesteringMarch.class));
cards.add(new SetCardInfo("Fleshwrither", 84, Rarity.UNCOMMON, mage.cards.f.Fleshwrither.class));
diff --git a/Mage.Sets/src/mage/sets/Unstable.java b/Mage.Sets/src/mage/sets/Unstable.java
index 4b7601ef9f..e3400540bf 100644
--- a/Mage.Sets/src/mage/sets/Unstable.java
+++ b/Mage.Sets/src/mage/sets/Unstable.java
@@ -60,7 +60,7 @@ public class Unstable extends ExpansionSet {
cards.add(new SetCardInfo("Earl of Squirrel", 108, Rarity.RARE, mage.cards.e.EarlOfSquirrel.class));
cards.add(new SetCardInfo("Forest", 216, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false)));
cards.add(new SetCardInfo("GO TO JAIL", 8, Rarity.COMMON, mage.cards.g.GOTOJAIL.class));
- cards.add(new SetCardInfo("Garbage Elemental", 82, Rarity.UNCOMMON, mage.cards.g.GarbageElemental.class));
+ cards.add(new SetCardInfo("Garbage Elemental", "82c", Rarity.UNCOMMON, mage.cards.g.GarbageElementalC.class));
cards.add(new SetCardInfo("Ground Pounder", 110, Rarity.COMMON, mage.cards.g.GroundPounder.class));
cards.add(new SetCardInfo("Hammer Helper", 85, Rarity.COMMON, mage.cards.h.HammerHelper.class));
cards.add(new SetCardInfo("Hydradoodle", 112, Rarity.RARE, mage.cards.h.Hydradoodle.class));
@@ -81,7 +81,7 @@ public class Unstable extends ExpansionSet {
cards.add(new SetCardInfo("Sword of Dungeons & Dragons", 1, Rarity.MYTHIC, mage.cards.s.SwordOfDungeonsAndDragons.class));
cards.add(new SetCardInfo("Target Minotaur", 98, Rarity.COMMON, mage.cards.t.TargetMinotaur.class));
cards.add(new SetCardInfo("Time Out", 48, Rarity.COMMON, mage.cards.t.TimeOut.class));
- cards.add(new SetCardInfo("Very Cryptic Command", 49, Rarity.RARE, mage.cards.v.VeryCrypticCommand.class));
+ cards.add(new SetCardInfo("Very Cryptic Command", "49d", Rarity.RARE, mage.cards.v.VeryCrypticCommandD.class));
cards.add(new SetCardInfo("Willing Test Subject", 126, Rarity.COMMON, mage.cards.w.WillingTestSubject.class));
cards.add(new SetCardInfo("capital offense", 52, Rarity.COMMON, mage.cards.c.CapitalOffense.class));
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UnearthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UnearthTest.java
index c25fa594fe..6ea4619197 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UnearthTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/UnearthTest.java
@@ -36,19 +36,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*
* @author LevelX2
*/
-
public class UnearthTest extends CardTestPlayerBase {
/**
- * Hellspark Elemental (and probably other cards with the unearth ability) - If I unearth the elemental,
- * attack, and then go to the end of my turn both the "sacrifice" and "exile" clauses will trigger and
- * the game will ask me which one I want to put on the stack first. If I choose "sacrifice" first and
- * "exile" second, all good, the exile part resolves first and the elemental is exiled, the sacrifice
- * part does nothing afterwards. But if I choose "exile" first and "sacrifice" second then the elemental
- * will be sacrificed and placed on my graveyard and after that the "exile" resolves but does nothing, as
- * I'm guessing it can't "find" the elemental anymore and so it stays in my graveyard, despite the fact
- * that because I use its unearth ability it should always be exiled once leaving the battlefield no matter what.
- * The bug should be easy to reproduce if following the order I mention above (click the exile part,
+ * Hellspark Elemental (and probably other cards with the unearth ability) -
+ * If I unearth the elemental, attack, and then go to the end of my turn
+ * both the "sacrifice" and "exile" clauses will trigger and the game will
+ * ask me which one I want to put on the stack first. If I choose
+ * "sacrifice" first and "exile" second, all good, the exile part resolves
+ * first and the elemental is exiled, the sacrifice part does nothing
+ * afterwards. But if I choose "exile" first and "sacrifice" second then the
+ * elemental will be sacrificed and placed on my graveyard and after that
+ * the "exile" resolves but does nothing, as I'm guessing it can't "find"
+ * the elemental anymore and so it stays in my graveyard, despite the fact
+ * that because I use its unearth ability it should always be exiled once
+ * leaving the battlefield no matter what. The bug should be easy to
+ * reproduce if following the order I mention above (click the exile part,
* so the sacrifice goes on the top of the stack).
*/
@Test
@@ -56,15 +59,15 @@ public class UnearthTest extends CardTestPlayerBase {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
// 3/1 - Trample, haste
// At the beginning of the end step, sacrifice Hellspark Elemental.
- // Unearth {1}{R} ({1}{R}: Return this card from your graveyard to the battlefield.
- // It gains haste. Exile it at the beginning of the next end step or if it would
- // leave the battlefield. Unearth only as a sorcery.)
+ // Unearth {1}{R} ({1}{R}: Return this card from your graveyard to the battlefield.
+ // It gains haste. Exile it at the beginning of the next end step or if it would
+ // leave the battlefield. Unearth only as a sorcery.)
addCard(Zone.GRAVEYARD, playerA, "Hellspark Elemental", 1);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
-
+
attack(1, playerA, "Hellspark Elemental");
-
+
setStopAt(2, PhaseStep.UNTAP);
execute();
@@ -74,22 +77,23 @@ public class UnearthTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Hellspark Elemental", 0);
assertExileCount("Hellspark Elemental", 1);
}
-
+
/**
- * Reported bug: Cards with unearth (e.g. Undead Leotau) are currently bugged. When you bring a creature back from the graveyard
- * with unearth, it [should] get exiled at end of turn normally, [but instead] a copy of the card stays on the battlefield
- * under your control permanently.
+ * Reported bug: Cards with unearth (e.g. Undead Leotau) are currently
+ * bugged. When you bring a creature back from the graveyard with unearth,
+ * it [should] get exiled at end of turn normally, [but instead] a copy of
+ * the card stays on the battlefield under your control permanently.
*/
@Test
public void testUndeadLeotau() {
-
+
//{R}: Undead Leotau gets +1/-1 until end of turn.
// Unearth {2}{B}
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.GRAVEYARD, playerA, "Undead Leotau", 1); // 3/4
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
attack(1, playerA, "Undead Leotau");
-
+
setStopAt(2, PhaseStep.UNTAP);
execute();
@@ -97,6 +101,35 @@ public class UnearthTest extends CardTestPlayerBase {
assertLife(playerB, 17);
assertPermanentCount(playerA, "Undead Leotau", 0);
- assertExileCount("Undead Leotau", 1);
+ assertExileCount("Undead Leotau", 1);
}
-}
\ No newline at end of file
+
+ /**
+ * At start of the end phase, creatures phased out by Teferi's Veil still
+ * exiled by unearth if they were put to battlefield by unearth.
+ *
+ * http://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/294911-teferis-veil-and-unearth
+ */
+ @Test
+ public void testUnearthWithPhasing() {
+ // Whenever a creature you control attacks, it phases out at end of combat.
+ addCard(Zone.BATTLEFIELD, playerA, "Teferi's Veil", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
+ // Unearth {B} ({B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.)
+ addCard(Zone.GRAVEYARD, playerA, "Dregscape Zombie", 1); // 2/1
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Unearth");
+ attack(1, playerA, "Dregscape Zombie");
+
+ setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+
+ assertGraveyardCount(playerA, "Dregscape Zombie", 0);
+ assertLife(playerB, 18);
+ assertExileCount("Dregscape Zombie", 0);
+
+ assertPermanentCount(playerA, "Dregscape Zombie", 1);
+
+ }
+
+}
diff --git a/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java b/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java
index cc62092fee..dda7c8283b 100644
--- a/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/CastOnlyDuringPhaseStepSourceAbility.java
@@ -1,7 +1,29 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * 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.abilities.common;
diff --git a/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueAbility.java b/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueAbility.java
new file mode 100644
index 0000000000..247d1bd842
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueAbility.java
@@ -0,0 +1,59 @@
+/*
+ * 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.abilities.common;
+
+import mage.abilities.condition.Condition;
+import mage.constants.Zone;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CastOnlyIfConditionIsTrueAbility extends SimpleStaticAbility {
+
+ public CastOnlyIfConditionIsTrueAbility(Condition condition) {
+ this(condition, null);
+ }
+
+ public CastOnlyIfConditionIsTrueAbility(Condition condition, String effectText) {
+ super(Zone.ALL, new CastOnlyIfConditionIsTrueEffect(condition));
+ this.setRuleAtTheTop(true);
+ if (effectText != null) {
+ getEffects().get(0).setText(effectText);
+ }
+ }
+
+ private CastOnlyIfConditionIsTrueAbility(final CastOnlyIfConditionIsTrueAbility ability) {
+ super(ability);
+ }
+
+ @Override
+ public CastOnlyIfConditionIsTrueAbility copy() {
+ return new CastOnlyIfConditionIsTrueAbility(this);
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueEffect.java b/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueEffect.java
new file mode 100644
index 0000000000..0fdc05f760
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/common/CastOnlyIfConditionIsTrueEffect.java
@@ -0,0 +1,85 @@
+/*
+ * 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.abilities.common;
+
+import mage.abilities.Ability;
+import mage.abilities.condition.Condition;
+import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
+import mage.constants.Duration;
+import mage.constants.Outcome;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class CastOnlyIfConditionIsTrueEffect extends ContinuousRuleModifyingEffectImpl {
+
+ private final Condition condition;
+
+ public CastOnlyIfConditionIsTrueEffect(Condition condition) {
+ super(Duration.EndOfGame, Outcome.Detriment);
+ this.condition = condition;
+ staticText = setText();
+ }
+
+ private CastOnlyIfConditionIsTrueEffect(final CastOnlyIfConditionIsTrueEffect effect) {
+ super(effect);
+ this.condition = effect.condition;
+ }
+
+ @Override
+ public boolean checksEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.CAST_SPELL;
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ // has to return true, if the spell cannot be cast in the current phase / step
+ if (event.getSourceId().equals(source.getSourceId())) {
+ if (condition != null && !condition.apply(game, source)) {
+ return true;
+ }
+ }
+ return false; // cast not prevented by this effect
+ }
+
+ @Override
+ public CastOnlyIfConditionIsTrueEffect copy() {
+ return new CastOnlyIfConditionIsTrueEffect(this);
+ }
+
+ private String setText() {
+ StringBuilder sb = new StringBuilder("cast {this} only ");
+ if (condition != null) {
+ sb.append(' ').append(condition.toString());
+ }
+ return sb.toString();
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentsComparedToOpponentsCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentsComparedToOpponentsCondition.java
new file mode 100644
index 0000000000..1acd1f596c
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentsComparedToOpponentsCondition.java
@@ -0,0 +1,76 @@
+/*
+ * 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.abilities.condition.common;
+
+import java.util.UUID;
+import mage.abilities.Ability;
+import mage.abilities.condition.Condition;
+import mage.constants.ComparisonType;
+import mage.filter.FilterPermanent;
+import mage.game.Game;
+import mage.players.Player;
+
+/**
+ *
+ * @author LevelX2
+ */
+public class ControlsPermanentsComparedToOpponentsCondition implements Condition {
+
+ private final ComparisonType type;
+ private final FilterPermanent filterPermanent;
+
+ public ControlsPermanentsComparedToOpponentsCondition(ComparisonType type, FilterPermanent filterPermanent) {
+ this.type = type;
+ this.filterPermanent = filterPermanent;
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player controller = game.getPlayer(source.getControllerId());
+ if (controller != null) {
+ int ownNumber = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game);
+ for (UUID playerId : game.getOpponents(source.getControllerId())) {
+ if (!ComparisonType.compare(ownNumber, type, game.getBattlefield().countAll(filterPermanent, playerId, game))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("if you control ");
+ sb.append(type.getText1()).append(" ");
+ sb.append(filterPermanent.getMessage()).append(" ");
+ sb.append(type.getText2());
+ sb.append(" each opponent");
+ return sb.toString();
+ }
+
+}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceEffect.java
index 455d3a5466..2fea64e3f2 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ExileSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSourceEffect.java
@@ -34,6 +34,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.game.Game;
+import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
@@ -77,6 +78,11 @@ public class ExileSourceEffect extends OneShotEffect {
if (controller != null) {
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
if (sourceObject instanceof Card) {
+ if (sourceObject instanceof Permanent) {
+ if (!((Permanent) sourceObject).isPhasedIn()) {
+ return true;
+ }
+ }
UUID exileZoneId = null;
String exileZoneName = "";
if (toUniqueExileZone) {
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeAttachedEffect.java
index 360091fca2..9b8c56f771 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeAttachedEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeAttachedEffect.java
@@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
-
package mage.abilities.effects.common.continuous;
import mage.abilities.Ability;
@@ -38,8 +37,9 @@ import mage.game.permanent.Permanent;
* @author nantuko
*/
public class AddCardTypeAttachedEffect extends ContinuousEffectImpl {
- private CardType addedCardType;
- private AttachmentType attachmentType;
+
+ private final CardType addedCardType;
+ private final AttachmentType attachmentType;
public AddCardTypeAttachedEffect(CardType addedCardType, Duration duration, AttachmentType attachmentType) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
@@ -59,8 +59,9 @@ public class AddCardTypeAttachedEffect extends ContinuousEffectImpl {
Permanent equipment = game.getPermanent(source.getSourceId());
if (equipment != null && equipment.getAttachedTo() != null) {
Permanent target = game.getPermanent(equipment.getAttachedTo());
- if (target != null && !target.getCardType().contains(addedCardType))
+ if (target != null && !target.getCardType().contains(addedCardType)) {
target.addCardType(addedCardType);
+ }
}
return true;
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
index 6fe7d4d7ab..4858b6e169 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
@@ -1,90 +1,112 @@
-/*
- * 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.abilities.effects.common.continuous;
-
-import mage.MageObjectReference;
-import mage.abilities.Ability;
-import mage.abilities.Mode;
-import mage.abilities.effects.ContinuousEffectImpl;
-import mage.constants.*;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
-
-/**
- * @author emerald000
- */
-public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
-
- private final CardType addedCardType;
-
- public AddCardTypeSourceEffect(CardType addedCardType, Duration duration) {
- super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
- this.addedCardType = addedCardType;
- if (addedCardType == CardType.ENCHANTMENT) {
- dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
- }
- }
-
- public AddCardTypeSourceEffect(final AddCardTypeSourceEffect effect) {
- super(effect);
- this.addedCardType = effect.addedCardType;
- }
-
- @Override
- public void init(Ability source, Game game) {
- super.init(source, game);
- affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()), game));
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent permanent = game.getPermanent(source.getSourceId());
- if (permanent != null && affectedObjectList.contains(new MageObjectReference(permanent, game))) {
- permanent.addCardType(addedCardType);
- return true;
- } else if (this.getDuration() == Duration.Custom) {
- this.discard();
- }
- return false;
- }
-
- @Override
- public AddCardTypeSourceEffect copy() {
- return new AddCardTypeSourceEffect(this);
- }
-
- @Override
- public String getText(Mode mode) {
- if (staticText != null && !staticText.isEmpty()) {
- return staticText;
- }
- StringBuilder sb = new StringBuilder();
- sb.append("{this} becomes ").append(addedCardType.toString()).append(" in addition to its other types " + this.getDuration().toString());
- return sb.toString();
- }
-}
+/*
+ * 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.abilities.effects.common.continuous;
+
+import java.util.ArrayList;
+import mage.MageObjectReference;
+import mage.abilities.Ability;
+import mage.abilities.Mode;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.constants.*;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+
+/**
+ * @author emerald000
+ */
+public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
+
+ private final ArrayList addedCardTypes = new ArrayList<>();
+
+ public AddCardTypeSourceEffect(Duration duration, CardType... addedCardType) {
+ super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
+ for (CardType cardType : addedCardType) {
+ this.addedCardTypes.add(cardType);
+ if (cardType == CardType.ENCHANTMENT) {
+ dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
+ } else if (cardType == CardType.ARTIFACT) {
+ dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
+ }
+ }
+ }
+
+ public AddCardTypeSourceEffect(final AddCardTypeSourceEffect effect) {
+ super(effect);
+ this.addedCardTypes.addAll(effect.addedCardTypes);
+ }
+
+ @Override
+ public void init(Ability source, Game game) {
+ super.init(source, game);
+ affectedObjectList.add(new MageObjectReference(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()), game));
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Permanent permanent = game.getPermanent(source.getSourceId());
+ if (permanent != null && affectedObjectList.contains(new MageObjectReference(permanent, game))) {
+ for (CardType cardType : addedCardTypes) {
+ if (!permanent.getCardType().contains(cardType)) {
+ permanent.addCardType(cardType);
+ }
+ }
+ return true;
+ } else if (this.getDuration() == Duration.Custom) {
+ this.discard();
+ }
+ return false;
+ }
+
+ @Override
+ public AddCardTypeSourceEffect copy() {
+ return new AddCardTypeSourceEffect(this);
+ }
+
+ @Override
+ public String getText(Mode mode) {
+ if (staticText != null && !staticText.isEmpty()) {
+ return staticText;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("{this} becomes ");
+ boolean article = false;
+ for (CardType cardType : addedCardTypes) {
+ if (!article) {
+ if (cardType.toString().startsWith("A") || cardType.toString().startsWith("E")) {
+ sb.append("an ");
+ } else {
+ sb.append("a ");
+ }
+ article = true;
+ }
+ sb.append(cardType.toString().toLowerCase()).append(" ");
+ }
+ sb.append(" in addition to its other types ").append(this.getDuration().toString());
+ return sb.toString();
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeTargetEffect.java
index 33c325bdc4..24fd3a05d4 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeTargetEffect.java
@@ -27,6 +27,7 @@
*/
package mage.abilities.effects.common.continuous;
+import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
@@ -45,21 +46,24 @@ import mage.game.permanent.Permanent;
*/
public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
- private final CardType addedCardType;
+ private final ArrayList addedCardTypes = new ArrayList<>();
- public AddCardTypeTargetEffect(CardType addedCardType, Duration duration) {
+ public AddCardTypeTargetEffect(Duration duration, CardType... addedCardType) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
- this.addedCardType = addedCardType;
- if (addedCardType == CardType.ENCHANTMENT) {
- dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
- } else if (addedCardType == CardType.ARTIFACT) {
- dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
+ for (CardType cardType : addedCardType) {
+ this.addedCardTypes.add(cardType);
+ if (cardType == CardType.ENCHANTMENT) {
+ dependencyTypes.add(DependencyType.EnchantmentAddingRemoving);
+ } else if (cardType == CardType.ARTIFACT) {
+ dependencyTypes.add(DependencyType.ArtifactAddingRemoving);
+ }
}
+
}
public AddCardTypeTargetEffect(final AddCardTypeTargetEffect effect) {
super(effect);
- this.addedCardType = effect.addedCardType;
+ this.addedCardTypes.addAll(effect.addedCardTypes);
}
@Override
@@ -68,8 +72,10 @@ public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
for (UUID targetId : targetPointer.getTargets(game, source)) {
Permanent target = game.getPermanent(targetId);
if (target != null) {
- if (!target.getCardType().contains(addedCardType)) {
- target.addCardType(addedCardType);
+ for (CardType cardType : addedCardTypes) {
+ if (!target.getCardType().contains(cardType)) {
+ target.addCardType(cardType);
+ }
}
result = true;
}
@@ -93,7 +99,23 @@ public class AddCardTypeTargetEffect extends ContinuousEffectImpl {
return staticText;
}
StringBuilder sb = new StringBuilder();
- sb.append("Target ").append(mode.getTargets().get(0).getTargetName()).append(" becomes ").append(addedCardType.toString()).append(" in addition to its other types until end of turn");
+ sb.append("Target ").append(mode.getTargets().get(0).getTargetName()).append(" becomes ");
+ boolean article = false;
+ for (CardType cardType : addedCardTypes) {
+ if (!article) {
+ if (cardType.toString().startsWith("A") || cardType.toString().startsWith("E")) {
+ sb.append("an ");
+ } else {
+ sb.append("a ");
+ }
+ article = true;
+ }
+ sb.append(cardType.toString().toLowerCase()).append(" ");
+ }
+ sb.append("in addition to its other types");
+ if (getDuration().equals(Duration.EndOfTurn)) {
+ sb.append(" until end of turn");
+ }
return sb.toString();
}
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java
index 6b8f615222..4787c7579f 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyDuringPhaseStepSourceEffect.java
@@ -1,7 +1,29 @@
/*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
+ * 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.abilities.effects.common.ruleModifying;
diff --git a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java
index a17d5ad6e7..5175c3ce81 100644
--- a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java
@@ -54,8 +54,8 @@ public class CrewAbility extends SimpleActivatedAbility {
private final int value;
public CrewAbility(int value) {
- super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect(CardType.ARTIFACT, Duration.EndOfTurn), new CrewCost(value));
- this.addEffect(new AddCardTypeSourceEffect(CardType.CREATURE, Duration.EndOfTurn));
+ super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT), new CrewCost(value));
+ this.addEffect(new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE));
this.value = value;
}
diff --git a/Mage/src/main/java/mage/cards/repository/CardCriteria.java b/Mage/src/main/java/mage/cards/repository/CardCriteria.java
index c0230c68d9..aa47af540b 100644
--- a/Mage/src/main/java/mage/cards/repository/CardCriteria.java
+++ b/Mage/src/main/java/mage/cards/repository/CardCriteria.java
@@ -44,6 +44,7 @@ import mage.constants.Rarity;
public class CardCriteria {
private String name;
+ private String nameExact;
private String rules;
private final List setCodes;
private final List types;
@@ -126,6 +127,11 @@ public class CardCriteria {
return this;
}
+ public CardCriteria nameExact(String nameExact) {
+ this.nameExact = nameExact;
+ return this;
+ }
+
public CardCriteria rules(String rules) {
this.rules = rules;
return this;
@@ -205,6 +211,10 @@ public class CardCriteria {
where.like("name", new SelectArg('%' + name + '%'));
clausesCount++;
}
+ if (nameExact != null) {
+ where.like("name", new SelectArg(nameExact));
+ clausesCount++;
+ }
if (rules != null) {
where.like("rules", new SelectArg('%' + rules + '%'));
clausesCount++;
@@ -231,7 +241,6 @@ public class CardCriteria {
clausesCount++;
}
-
if (types.size() != 7) { //if all types selected - no selection needed (Tribal and Conspiracy not selectable yet)
for (CardType type : types) {
where.like("types", new SelectArg('%' + type.name() + '%'));
@@ -315,15 +324,13 @@ public class CardCriteria {
where.eq("cardNumber", new SelectArg(0));
}
-
-
if (start != null) {
qb.offset(start);
}
if (count != null) {
qb.limit(count);
}
-
+
if (sortBy != null) {
qb.orderBy(sortBy, true);
}
diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java
index 7f50dec496..bb1e8eb74f 100644
--- a/Mage/src/main/java/mage/cards/repository/CardRepository.java
+++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java
@@ -58,7 +58,7 @@ public enum CardRepository {
// raise this if db structure was changed
private static final long CARD_DB_VERSION = 51;
// raise this if new cards were added to the server
- private static final long CARD_CONTENT_VERSION = 96;
+ private static final long CARD_CONTENT_VERSION = 97;
private Dao cardDao;
private Set classNames;
diff --git a/Mage/src/main/java/mage/constants/ComparisonType.java b/Mage/src/main/java/mage/constants/ComparisonType.java
index 7f62a51f2c..f47bd1839c 100644
--- a/Mage/src/main/java/mage/constants/ComparisonType.java
+++ b/Mage/src/main/java/mage/constants/ComparisonType.java
@@ -4,12 +4,16 @@ package mage.constants;
* Created by IGOUDT on 5-3-2017.
*/
public enum ComparisonType {
- MORE_THAN(">"), FEWER_THAN("<"), EQUAL_TO("==");
+ MORE_THAN(">", "more", "than"), FEWER_THAN("<", "fewer", "than"), EQUAL_TO("==", "equal", "to");
String operator;
+ String text1;
+ String text2;
- ComparisonType(String op) {
- operator = op;
+ ComparisonType(String op, String text1, String text2) {
+ this.operator = op;
+ this.text1 = text1;
+ this.text2 = text2;
}
@Override
@@ -17,6 +21,13 @@ public enum ComparisonType {
return operator;
}
+ public String getText1() {
+ return text1;
+ }
+
+ public String getText2() {
+ return text2;
+ }
public static boolean compare(int source, ComparisonType comparison, int target) {
switch (comparison) {
diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/ControllerIdPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/ControllerIdPredicate.java
index 1952990240..7eeb8729bf 100644
--- a/Mage/src/main/java/mage/filter/predicate/permanent/ControllerIdPredicate.java
+++ b/Mage/src/main/java/mage/filter/predicate/permanent/ControllerIdPredicate.java
@@ -27,11 +27,12 @@
*/
package mage.filter.predicate.permanent;
-import java.util.UUID;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
+import java.util.UUID;
+
/**
*
* @author North
@@ -46,6 +47,12 @@ public class ControllerIdPredicate implements Predicate {
@Override
public boolean apply(Permanent input, Game game) {
+ if(controllerId == null){
+ return false;
+ }
+ if(input.getControllerId() == null){
+ return false;
+ }
return controllerId.equals(input.getControllerId());
}
diff --git a/Mage/src/main/java/mage/game/command/emblems/TezzeretTheSchemerEmblem.java b/Mage/src/main/java/mage/game/command/emblems/TezzeretTheSchemerEmblem.java
index 82cab888b4..2de6910fdd 100644
--- a/Mage/src/main/java/mage/game/command/emblems/TezzeretTheSchemerEmblem.java
+++ b/Mage/src/main/java/mage/game/command/emblems/TezzeretTheSchemerEmblem.java
@@ -36,7 +36,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.constants.Zone;
-import mage.filter.common.FilterControlledArtifactPermanent;
+import static mage.filter.StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT;
import mage.game.command.Emblem;
import mage.target.TargetPermanent;
@@ -49,13 +49,13 @@ public class TezzeretTheSchemerEmblem extends Emblem {
public TezzeretTheSchemerEmblem() {
this.setName("Emblem Tezzeret");
- Effect effect = new AddCardTypeTargetEffect(CardType.CREATURE, Duration.EndOfGame);
+ Effect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE);
effect.setText("target artifact you control becomes an artifact creature");
Ability ability = new BeginningOfCombatTriggeredAbility(Zone.COMMAND, effect, TargetController.YOU, false, true);
effect = new SetPowerToughnessTargetEffect(5, 5, Duration.EndOfGame);
effect.setText("with base power and toughness 5/5");
ability.addEffect(effect);
- ability.addTarget(new TargetPermanent(new FilterControlledArtifactPermanent()));
+ ability.addTarget(new TargetPermanent(FILTER_CONTROLLED_PERMANENT_ARTIFACT));
this.getAbilities().add(ability);
}
}