From 78d036b6bb29b8d3ddca490b767936f9a89e79f3 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 1 Jan 2018 18:00:42 +0400 Subject: [PATCH 01/54] UI: fixed windows layer problems when old window overlapped new window (see #4318, #4320 and other) --- .../src/main/java/mage/client/MageFrame.java | 10 +++--- .../mage/client/dialog/AddLandDialog.java | 9 +++++- .../mage/client/dialog/ConnectDialog.java | 4 +-- .../java/mage/client/dialog/MageDialog.java | 32 ++++++++++++++++--- .../mage/client/dialog/PickChoiceDialog.java | 8 +++-- .../mage/client/dialog/PickNumberDialog.java | 11 ++++++- .../mage/client/dialog/PickPileDialog.java | 8 +++++ .../mage/client/dialog/ShowCardsDialog.java | 10 ++++-- .../main/java/mage/client/game/GamePanel.java | 2 +- 9 files changed, 74 insertions(+), 20 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 7df4a984ff0..5d4d579a47e 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); @@ -945,7 +945,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 +953,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 +1096,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/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java index ed9742124f7..cb39ef8eb85 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java @@ -114,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); } 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 7a453e38435..867698822d2 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() { 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 ef6e29b4268..5deaed81aa3 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/PickChoiceDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java index 60cadbfa3d0..80a28468f9e 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,7 +178,7 @@ public class PickChoiceDialog extends MageDialog { this.setLocation(centered.x, centered.y); GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); } - + // final load loadData(); 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 018c2bb44ec..f4e3244fb19 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 9fcfdfdd24b..ff3682272ca 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 d26d318012b..f185bf2556f 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 ab0daf3e706..3509af9c288 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 } } From 56d214f0b25f142e3680f8fee098fc56d08fa40e Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 1 Jan 2018 18:02:20 +0400 Subject: [PATCH 02/54] UI: added set search button in new tournament dialog --- .../client/dialog/NewTournamentDialog.java | 124 ++++++++++++++---- 1 file changed, 95 insertions(+), 29 deletions(-) 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 5842ca75146..17a376f4dca 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()); } } From 1ad8529df8ea1afd628a311ac68227d3cde01f9b Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Mon, 1 Jan 2018 20:51:56 +0400 Subject: [PATCH 03/54] Fixed chrismas time fail on new year :-( --- .../src/main/java/mage/client/MageFrame.java | 17 +++++--- .../java/mage/client/util/ChrismasTest.java | 42 +++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 Mage.Client/src/test/java/mage/client/util/ChrismasTest.java diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 5d4d579a47e..9c5d93d6fe4 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -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"; 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 00000000000..93d4b26c708 --- /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))); + } + +} From c08c5a149b129b4478e2213b9c9dabbf43ea1e36 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:11:49 +0100 Subject: [PATCH 04/54] Fixed Heroism ability tax cost --- Mage.Sets/src/mage/cards/h/Heroism.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/cards/h/Heroism.java b/Mage.Sets/src/mage/cards/h/Heroism.java index 34ac472c957..cb1c9ef02bf 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)) { From 2fcbd6535f72d1e8abedb35544face6d14a470e9 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:15:09 +0100 Subject: [PATCH 05/54] Implemented Merseine --- Mage.Sets/src/mage/cards/m/Merseine.java | 172 +++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/Merseine.java diff --git a/Mage.Sets/src/mage/cards/m/Merseine.java b/Mage.Sets/src/mage/cards/m/Merseine.java new file mode 100644 index 00000000000..dca22e5da9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Merseine.java @@ -0,0 +1,172 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class Merseine extends CardImpl { + + public Merseine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Merseine enters the battlefield with three net counters on it. + Effect effect = new AddCountersSourceEffect(CounterType.ECHO.createInstance(3)); + effect.setText("with three net counters on it"); + this.addAbility(new EntersBattlefieldAbility(effect)); + + // Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), + new SourceHasCounterCondition(CounterType.ECHO)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it"))); + + // Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature. + SimpleActivatedAbility ability = new MerseineActivatedAbility(); + ability.setMayActivate(TargetController.ANY); + this.addAbility(ability); + } + + public Merseine(final Merseine card) { + super(card); + } + + @Override + public Merseine copy() { + return new Merseine(this); + } +} + +class MerseineActivatedAbility extends SimpleActivatedAbility { + + public MerseineActivatedAbility() { + super(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.ECHO.createInstance()), new MerseineCost()); + } + + private MerseineActivatedAbility(final MerseineActivatedAbility ability) { + super(ability); + } + + @Override + public Effects getEffects(Game game, EffectType effectType) { + return super.getEffects(game, effectType); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + Permanent sourcePermanent = game.getBattlefield().getPermanent(this.getSourceId()); + if (sourcePermanent != null) { + Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo()); + if (attachedTo != null) { + return super.canActivate(attachedTo.getControllerId(), game); + } + } + return false; + } + + @Override + public MerseineActivatedAbility copy() { + return new MerseineActivatedAbility(this); + } + + @Override + public String getRule() { + return "Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature."; + } +} + +class MerseineCost extends CostImpl { + + public MerseineCost() { + this.text = "Pay enchanted creature's mana cost"; + } + + public MerseineCost(final MerseineCost cost) { + super(cost); + } + + @Override + public MerseineCost copy() { + return new MerseineCost(this); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Permanent sourcePermanent = game.getBattlefield().getPermanent(sourceId); + if (sourcePermanent != null) { + Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo()); + if (attachedTo != null) { + return attachedTo.getManaCost().canPay(ability, sourceId, controllerId, game); + } + } + return false; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Permanent sourcePermanent = game.getBattlefield().getPermanent(sourceId); + if (sourcePermanent != null) { + Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo()); + if (attachedTo != null) { + paid = attachedTo.getManaCost().pay(ability, game, sourceId, controllerId, noMana); + } + } + return paid; + } +} From dce22b38524ff788e32a88161ec9582b034c070b Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:15:59 +0100 Subject: [PATCH 06/54] Implemented Raiding Party --- Mage.Sets/src/mage/cards/r/RaidingParty.java | 160 +++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RaidingParty.java diff --git a/Mage.Sets/src/mage/cards/r/RaidingParty.java b/Mage.Sets/src/mage/cards/r/RaidingParty.java new file mode 100644 index 00000000000..2db0dfd4c10 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaidingParty.java @@ -0,0 +1,160 @@ +/* + * 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.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CantBeTargetedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterObject; +import mage.filter.FilterStackObject; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class RaidingParty extends CardImpl { + + private static final FilterObject filterWhite = new FilterStackObject("white spells or abilities from white sources"); + private static final FilterControlledCreaturePermanent filterOrc = new FilterControlledCreaturePermanent("an Orc"); + + static { + filterWhite.add(new ColorPredicate(ObjectColor.WHITE)); + filterOrc.add(new SubtypePredicate(SubType.ORC)); + } + + public RaidingParty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + + // Raiding Party can't be the target of white spells or abilities from white sources. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedSourceEffect(filterWhite, Duration.WhileOnBattlefield))); + + // Sacrifice an Orc: Each player may tap any number of untapped white creatures he or she controls. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren't chosen this way by any player. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RaidingPartyEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1, filterOrc, true)))); + } + + public RaidingParty(final RaidingParty card) { + super(card); + } + + @Override + public RaidingParty copy() { + return new RaidingParty(this); + } +} + +class RaidingPartyEffect extends OneShotEffect { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creatures"); + private static final FilterPermanent filter2 = new FilterPermanent("Plains"); + + static { + filter.add(Predicates.not(new TappedPredicate())); + filter.add(new ColorPredicate(ObjectColor.WHITE)); + filter2.add(new SubtypePredicate(SubType.PLAINS)); + } + + RaidingPartyEffect() { + super(Outcome.Detriment); + staticText = "Each player may tap any number of untapped white creatures he or she controls. For each creature tapped this way, that player chooses up to two Plains. Then destroy all Plains that weren't chosen this way by any player"; + } + + RaidingPartyEffect(RaidingPartyEffect effect) { + super(effect); + } + + @Override + public RaidingPartyEffect copy() { + return new RaidingPartyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent != null) { + Set plainsToSave = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); + int tappedCount = 0; + Target untappedCreatureTarget = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + if (player.choose(Outcome.Benefit, untappedCreatureTarget, source.getSourceId(), game)) { + tappedCount = untappedCreatureTarget.getTargets().size(); + for (UUID creatureId : untappedCreatureTarget.getTargets()) { + Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); + if (creature != null) { + creature.tap(game); + } + } + } + if (tappedCount > 0) { + Target plainsToSaveTarget = new TargetPermanent(0, tappedCount * 2, filter2, true); + if (player.choose(Outcome.Benefit, plainsToSaveTarget, source.getSourceId(), game)) { + for (UUID plainsId : plainsToSaveTarget.getTargets()) { + plainsToSave.add(plainsId); + } + } + } + } + } + for (Permanent plains : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source.getSourceId(), game)) { + if (!plainsToSave.contains(plains.getId())) { + plains.destroy(source.getSourceId(), game, false); + } + } + return true; + } + return false; + } +} From f66f5cf2185d72e1a026198bc22477477e10e9e7 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:16:36 +0100 Subject: [PATCH 07/54] Implemented Tidal Flats --- Mage.Sets/src/mage/cards/t/TidalFlats.java | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TidalFlats.java diff --git a/Mage.Sets/src/mage/cards/t/TidalFlats.java b/Mage.Sets/src/mage/cards/t/TidalFlats.java new file mode 100644 index 00000000000..d33db8fa398 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TidalFlats.java @@ -0,0 +1,144 @@ +/* + * 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.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +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.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class TidalFlats extends CardImpl { + + public TidalFlats(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}"); + + // {U}{U}: For each attacking creature without flying, its controller may pay {1}. If he or she doesn't, creatures you control blocking that creature gain first strike until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new TidalFlatsEffect(), new ManaCostsImpl("{U}{U}"))); + } + + public TidalFlats(final TidalFlats card) { + super(card); + } + + @Override + public TidalFlats copy() { + return new TidalFlats(this); + } +} + +class TidalFlatsEffect extends OneShotEffect { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking creature without flying"); + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public TidalFlatsEffect() { + super(Outcome.Benefit); + this.staticText = "For each attacking creature without flying, its controller may pay {1}. If he or she doesn't, creatures you control blocking that creature gain first strike until end of turn"; + } + + public TidalFlatsEffect(final TidalFlatsEffect effect) { + super(effect); + } + + @Override + public TidalFlatsEffect copy() { + return new TidalFlatsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getPlayerList(); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Player player = game.getPlayer(game.getActivePlayerId()); + Cost cost = new ManaCostsImpl("{1}"); + List affectedPermanents = new ArrayList<>(); + for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, player.getId(), game)) { + cost.clearPaid(); + String message = "Pay " + cost.getText() + " for " + permanent.getLogName() + "? If you don't, creatures " + controller.getLogName() + " controls blocking it gain first strike until end of turn."; + if (player != null && player.chooseUse(Outcome.Benefit, message, source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName()); + continue; + } else { + game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName()); + affectedPermanents.add(permanent); + } + } else { + game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName()); + affectedPermanents.add(permanent); + } + } + + for (Permanent permanent : affectedPermanents) { + CombatGroup group = game.getCombat().findGroup(permanent.getId()); + if (group != null) { + for (UUID blockerId : group.getBlockers()) { + Permanent blocker = game.getPermanent(blockerId); + if (blocker != null && blocker.getControllerId() == controller.getId()) { + ContinuousEffect effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(blocker.getId())); + game.addEffect(effect, source); + } + } + } + + } + return true; + } + return false; + } +} From ec8d2032ebe4e31d0ffca30090980c0f664bf986 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:17:19 +0100 Subject: [PATCH 08/54] Implemented Thelon's Chant --- Mage.Sets/src/mage/cards/t/ThelonsChant.java | 126 +++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/ThelonsChant.java diff --git a/Mage.Sets/src/mage/cards/t/ThelonsChant.java b/Mage.Sets/src/mage/cards/t/ThelonsChant.java new file mode 100644 index 00000000000..578450e8b1a --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThelonsChant.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.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class ThelonsChant extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("a Swamp"); + + static{ + filter.add(new SubtypePredicate(SubType.SWAMP)); + } + + public ThelonsChant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{G}"); + + // At the beginning of your upkeep, sacrifice Thelon's Chant unless you pay {G}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{G}")), TargetController.YOU, false)); + + // Whenever a player puts a Swamp onto the battlefield, Thelon's Chant deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new ThelonsChantEffect(), filter, false, SetTargetPointer.PLAYER, + "Whenever a player puts a Swamp onto the battlefield, {this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls.")); + } + + public ThelonsChant(final ThelonsChant card) { + super(card); + } + + @Override + public ThelonsChant copy() { + return new ThelonsChant(this); + } +} + +class ThelonsChantEffect extends OneShotEffect { + + public ThelonsChantEffect() { + super(Outcome.Damage); + staticText = "{this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls"; + } + + public ThelonsChantEffect(final ThelonsChantEffect effect) { + super(effect); + } + + @Override + public ThelonsChantEffect copy() { + return new ThelonsChantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (player != null && sourcePermanent != null) { + boolean paid = false; + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + if (player.chooseUse(Outcome.Detriment, "Put a -1/-1 counter on a creature you control? (otherwise " + sourcePermanent.getLogName() + " deals 3 damage to you)", source, game) + && player.choose(Outcome.UnboostCreature, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(CounterType.M1M1.createInstance(), source, game); + paid = true; + } + } + if (!paid) { + player.damage(3, source.getSourceId(), game, false, true); + } + return true; + } + return false; + } +} From 2421953efb51a80b605ec93b923c48552eac8101 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:18:01 +0100 Subject: [PATCH 09/54] Implemented Tourach's Chant --- Mage.Sets/src/mage/cards/t/TourachsChant.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TourachsChant.java diff --git a/Mage.Sets/src/mage/cards/t/TourachsChant.java b/Mage.Sets/src/mage/cards/t/TourachsChant.java new file mode 100644 index 00000000000..53219c5ee95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TourachsChant.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.t; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public class TourachsChant extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("a Forest"); + + static{ + filter.add(new SubtypePredicate(SubType.FOREST)); + } + + public TourachsChant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + + // At the beginning of your upkeep, sacrifice Tourach's Chant unless you pay {B}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{B}")), TargetController.YOU, false)); + + // Whenever a player puts a Forest onto the battlefield, Tourach's Chant deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new TourachsChantEffect(), filter, false, SetTargetPointer.PLAYER, + "Whenever a player puts a Forest onto the battlefield, {this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls.")); + } + + public TourachsChant(final TourachsChant card) { + super(card); + } + + @Override + public TourachsChant copy() { + return new TourachsChant(this); + } +} + +class TourachsChantEffect extends OneShotEffect { + + public TourachsChantEffect() { + super(Outcome.Damage); + staticText = "{this} deals 3 damage to that player unless he or she puts a -1/-1 counter on a creature he or she controls"; + } + + public TourachsChantEffect(final TourachsChantEffect effect) { + super(effect); + } + + @Override + public TourachsChantEffect copy() { + return new TourachsChantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (player != null && sourcePermanent != null) { + boolean paid = false; + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + if (player.chooseUse(Outcome.Detriment, "Put a -1/-1 counter on a creature you control? (otherwise " + sourcePermanent.getLogName() + " deals 3 damage to you)", source, game) + && player.choose(Outcome.UnboostCreature, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(CounterType.M1M1.createInstance(), source, game); + paid = true; + } + } + if (!paid) { + player.damage(3, source.getSourceId(), game, false, true); + } + return true; + } + return false; + } +} From 231bbeb88d1a04c5e720c42f2233f193ca6a7d2b Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 18:20:09 +0100 Subject: [PATCH 10/54] Implemented cards --- Mage.Sets/src/mage/sets/FallenEmpires.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Mage.Sets/src/mage/sets/FallenEmpires.java b/Mage.Sets/src/mage/sets/FallenEmpires.java index 8aed048f3cb..fc24356ba2b 100644 --- a/Mage.Sets/src/mage/sets/FallenEmpires.java +++ b/Mage.Sets/src/mage/sets/FallenEmpires.java @@ -188,6 +188,10 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Initiates of the Ebon Hand", 16, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Initiates of the Ebon Hand", 17, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Initiates of the Ebon Hand", 18, Rarity.COMMON, InitiatesOfTheEbonHand.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Merseine", 47, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Merseine", 48, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Merseine", 49, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Merseine", 50, Rarity.COMMON, mage.cards.m.Merseine.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mindstab Thrull", 19, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mindstab Thrull", 20, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mindstab Thrull", 21, Rarity.COMMON, MindstabThrull.class, NON_FULL_USE_VARIOUS)); @@ -212,6 +216,7 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Order of the Ebon Hand", 26, Rarity.COMMON, OrderOfTheEbonHand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Order of the Ebon Hand", 27, Rarity.COMMON, OrderOfTheEbonHand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Orgg", 131, Rarity.RARE, mage.cards.o.Orgg.class)); + cards.add(new SetCardInfo("Raiding Party", 132, Rarity.UNCOMMON, mage.cards.r.RaidingParty.class)); cards.add(new SetCardInfo("Rainbow Vale", 184, Rarity.RARE, mage.cards.r.RainbowVale.class)); cards.add(new SetCardInfo("Ring of Renewal", 174, Rarity.RARE, mage.cards.r.RingOfRenewal.class)); cards.add(new SetCardInfo("River Merfolk", 51, Rarity.RARE, mage.cards.r.RiverMerfolk.class)); @@ -233,6 +238,7 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Thallid Devourer", 91, Rarity.UNCOMMON, mage.cards.t.ThallidDevourer.class)); cards.add(new SetCardInfo("Thelonite Druid", 92, Rarity.UNCOMMON, mage.cards.t.TheloniteDruid.class)); cards.add(new SetCardInfo("Thelonite Monk", 93, Rarity.RARE, mage.cards.t.TheloniteMonk.class)); + cards.add(new SetCardInfo("Thelon's Chant", 94, Rarity.UNCOMMON, mage.cards.t.ThelonsChant.class)); cards.add(new SetCardInfo("Thelon's Curse", 95, Rarity.RARE, mage.cards.t.ThelonsCurse.class)); cards.add(new SetCardInfo("Thorn Thallid", 96, Rarity.COMMON, ThornThallid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thorn Thallid", 97, Rarity.COMMON, ThornThallid.class, NON_FULL_USE_VARIOUS)); @@ -241,7 +247,11 @@ public class FallenEmpires extends ExpansionSet { cards.add(new SetCardInfo("Thrull Champion", 29, Rarity.RARE, mage.cards.t.ThrullChampion.class)); cards.add(new SetCardInfo("Thrull Retainer", 30, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); cards.add(new SetCardInfo("Thrull Wizard", 31, Rarity.UNCOMMON, mage.cards.t.ThrullWizard.class)); + cards.add(new SetCardInfo("Tidal Flats", 54, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidal Flats", 55, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tidal Flats", 56, Rarity.COMMON, mage.cards.t.TidalFlats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tidal Influence", 57, Rarity.UNCOMMON, mage.cards.t.TidalInfluence.class)); + cards.add(new SetCardInfo("Tourach's Chant", 32, Rarity.UNCOMMON, mage.cards.t.TourachsChant.class)); cards.add(new SetCardInfo("Tourach's Gate", 33, Rarity.RARE, mage.cards.t.TourachsGate.class)); cards.add(new SetCardInfo("Vodalian Knights", 58, Rarity.RARE, mage.cards.v.VodalianKnights.class)); cards.add(new SetCardInfo("Vodalian Mage", 59, Rarity.COMMON, VodalianMage.class, NON_FULL_USE_VARIOUS)); From 49aa22079fb6146ff67246d4ac1cefe84bfd253a Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 19:09:08 +0100 Subject: [PATCH 11/54] Added net counter --- Mage/src/main/java/mage/counters/CounterType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 7a530dfde30..3b3f8f2f5d5 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -93,6 +93,7 @@ public enum CounterType { MINING("mining"), MIRE("mire"), MUSTER("muster"), + NET("net"), P0P1(new BoostCounter(0, 1).name), P1P0(new BoostCounter(1, 0).name), P1P1(new BoostCounter(1, 1).name), From 4289ad67d017ffc5b1e5777506699c94b9026fbc Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 19:10:02 +0100 Subject: [PATCH 12/54] Updated Merseine --- Mage.Sets/src/mage/cards/m/Merseine.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/m/Merseine.java b/Mage.Sets/src/mage/cards/m/Merseine.java index dca22e5da9d..f9a7ffb438c 100644 --- a/Mage.Sets/src/mage/cards/m/Merseine.java +++ b/Mage.Sets/src/mage/cards/m/Merseine.java @@ -69,13 +69,13 @@ public class Merseine extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Merseine enters the battlefield with three net counters on it. - Effect effect = new AddCountersSourceEffect(CounterType.ECHO.createInstance(3)); + Effect effect = new AddCountersSourceEffect(CounterType.NET.createInstance(3)); effect.setText("with three net counters on it"); this.addAbility(new EntersBattlefieldAbility(effect)); // Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), - new SourceHasCounterCondition(CounterType.ECHO)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it"))); + new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it"))); // Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature. SimpleActivatedAbility ability = new MerseineActivatedAbility(); @@ -96,7 +96,7 @@ public class Merseine extends CardImpl { class MerseineActivatedAbility extends SimpleActivatedAbility { public MerseineActivatedAbility() { - super(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.ECHO.createInstance()), new MerseineCost()); + super(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.NET.createInstance()), new MerseineCost()); } private MerseineActivatedAbility(final MerseineActivatedAbility ability) { From 3cd7ea7752507efbbfa985b160cded3bc1d3066e Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Mon, 1 Jan 2018 19:44:02 +0100 Subject: [PATCH 13/54] Added player announcements to Raiding Party --- Mage.Sets/src/mage/cards/r/RaidingParty.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mage.Sets/src/mage/cards/r/RaidingParty.java b/Mage.Sets/src/mage/cards/r/RaidingParty.java index 2db0dfd4c10..0552f432078 100644 --- a/Mage.Sets/src/mage/cards/r/RaidingParty.java +++ b/Mage.Sets/src/mage/cards/r/RaidingParty.java @@ -143,6 +143,10 @@ class RaidingPartyEffect extends OneShotEffect { if (player.choose(Outcome.Benefit, plainsToSaveTarget, source.getSourceId(), game)) { for (UUID plainsId : plainsToSaveTarget.getTargets()) { plainsToSave.add(plainsId); + Permanent plains = game.getPermanent(plainsId); + if (plains != null) { + game.informPlayers(player.getLogName() + " chose " + plains.getLogName() + " to not be destroyed by " + sourcePermanent.getLogName()); + } } } } From c1bf846973f797a995961399a491e7a25e3e7ddf Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 2 Jan 2018 00:14:29 +0400 Subject: [PATCH 14/54] UI: added new memory statistics, warnings and hints (see #4324) --- .../mage/client/util/stats/MemoryStats.java | 52 ++++++++++++++++++ .../util/stats/MemoryUsageStatUtil.java | 25 --------- .../client/util/stats/UpdateMemUsageTask.java | 55 ++++++++++++++++--- 3 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/util/stats/MemoryStats.java delete mode 100644 Mage.Client/src/main/java/mage/client/util/stats/MemoryUsageStatUtil.java diff --git a/Mage.Client/src/main/java/mage/client/util/stats/MemoryStats.java b/Mage.Client/src/main/java/mage/client/util/stats/MemoryStats.java new file mode 100644 index 00000000000..dfa53da2734 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/stats/MemoryStats.java @@ -0,0 +1,52 @@ +package mage.client.util.stats; + +/** + * + * @author JayDi85 + */ +public class MemoryStats { + + private float Available = 0; + private float MaxAvailable = 0; + private float Used = 0; + private float Free = 0; + + public MemoryStats(float MaxAvailable, float Available, float Used, float Free){ + this.setMaxAvailable(MaxAvailable); + this.setAvailable(Available); + this.setUsed(Used); + this.setFree(Free); + } + + public float getAvailable() { + return Available; + } + + public void setAvailable(float available) { + Available = available; + } + + public float getUsed() { + return Used; + } + + public void setUsed(float used) { + Used = used; + } + + public float getFree() { + return Free; + } + + public void setFree(float free) { + Free = free; + } + + public float getMaxAvailable() { + return MaxAvailable; + } + + public void setMaxAvailable(float maxAvailable) { + MaxAvailable = maxAvailable; + } +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/util/stats/MemoryUsageStatUtil.java b/Mage.Client/src/main/java/mage/client/util/stats/MemoryUsageStatUtil.java deleted file mode 100644 index 900b284fa9e..00000000000 --- a/Mage.Client/src/main/java/mage/client/util/stats/MemoryUsageStatUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -package mage.client.util.stats; - -/** - * @author noxx - */ -public final class MemoryUsageStatUtil { - - private MemoryUsageStatUtil() {} - - /** - * Returns percentage of available memory used at runtime. - * If not possible to determine, returns -1. - * - * @return - */ - public static float getMemoryFreeStatPercentage() { - Runtime runtime = Runtime.getRuntime(); - if (runtime.maxMemory() != 0) { - long usedMem = runtime.totalMemory() - runtime.freeMemory(); - return (1 - (1.0f*usedMem)/runtime.maxMemory())*100; - } else { - return -1; - } - } -} diff --git a/Mage.Client/src/main/java/mage/client/util/stats/UpdateMemUsageTask.java b/Mage.Client/src/main/java/mage/client/util/stats/UpdateMemUsageTask.java index 61b28bda4ed..31d62d24962 100644 --- a/Mage.Client/src/main/java/mage/client/util/stats/UpdateMemUsageTask.java +++ b/Mage.Client/src/main/java/mage/client/util/stats/UpdateMemUsageTask.java @@ -1,5 +1,6 @@ package mage.client.util.stats; +import java.awt.*; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -11,11 +12,13 @@ import org.apache.log4j.Logger; * This updates the mem usage info in the Mage client every * MEM_USAGE_UPDATE_TIME ms. * - * @author noxx + * @author noxx, JayDi85 */ -public class UpdateMemUsageTask extends SwingWorker { + +public class UpdateMemUsageTask extends SwingWorker { private static final int MEM_USAGE_UPDATE_TIME = 2000; + private static final int MEM_USAGE_WARNING_PERCENT = 80; // red color for mem used more than xx% private final JLabel jLabelToDisplayInfo; @@ -23,24 +26,60 @@ public class UpdateMemUsageTask extends SwingWorker { public UpdateMemUsageTask(JLabel jLabelToDisplayInfo) { this.jLabelToDisplayInfo = jLabelToDisplayInfo; + this.jLabelToDisplayInfo.setToolTipText("Memory usage statistics"); } @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { - float memUsage = MemoryUsageStatUtil.getMemoryFreeStatPercentage(); - this.publish(memUsage >= 0 ? memUsage : null); + MemoryStats memoryStats = new MemoryStats(0, 0, 0, 0); + + Runtime runtime = Runtime.getRuntime(); + if (runtime.maxMemory() != 0) { + memoryStats.setMaxAvailable(runtime.maxMemory()); + memoryStats.setAvailable(runtime.totalMemory()); + memoryStats.setFree(runtime.freeMemory()); + memoryStats.setUsed(runtime.totalMemory() - runtime.freeMemory()); + } + + this.publish(memoryStats); TimeUnit.MILLISECONDS.sleep(MEM_USAGE_UPDATE_TIME); } return null; } @Override - protected void process(List chunks) { + protected void process(List chunks) { if (chunks != null && !chunks.isEmpty()) { - Float memUsage = chunks.get(chunks.size() - 1); - if (memUsage != null) { - jLabelToDisplayInfo.setText(Math.round(memUsage) + "% Mem free"); + MemoryStats memoryStats = chunks.get(chunks.size() - 1); + if (memoryStats != null) { + int max = Math.round(memoryStats.getMaxAvailable() / (1000 * 1000)); + int used = Math.round(memoryStats.getUsed() / (1000 * 1000)); + int total = Math.round(memoryStats.getAvailable() / (1000 * 1000)); + int percent = 0; + if(max != 0){ + percent = Math.round((used * 100) / max); + } + + jLabelToDisplayInfo.setText("Memory used: " + percent + "% (" + used + " of " + max + " MB)"); + String warning = ""; + String optimizeHint = "

If you see low memory warning and have free system memory then try to increase max limit in launcher settings:
" + + " - Go to launcher -> settings -> java tab;
" + + " - Find client java options (it's may contain many commands);
" + + " - Find max available memory setting: -Xmx256m (it's must start with -Xmx);
" + + " - Increase number in that value from 256 to 512, or 512 to 1024;
" + + " - Save new settings and restart application."; + if(percent >= MEM_USAGE_WARNING_PERCENT){ + jLabelToDisplayInfo.setForeground(Color.red); + warning = "

WARNING
" + + "Application memory limit almost reached. Errors and freezes are very possible."; + + }else{ + jLabelToDisplayInfo.setForeground(Color.black); + } + + this.jLabelToDisplayInfo.setToolTipText("Memory usage statistics" + warning + optimizeHint); + return; } } From 9009d72c823612ee2149d5a1aa4bb10ed070aa0b Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 2 Jan 2018 00:15:44 +0400 Subject: [PATCH 15/54] UI: increased tooltip time before hide (60 secs) --- Mage.Client/src/main/java/mage/client/MageFrame.java | 6 ++++-- .../src/main/java/mage/client/constants/Constants.java | 3 +++ .../src/main/java/mage/client/game/HelperPanel.java | 7 ++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 9c5d93d6fe4..a15e4ba4f8f 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -50,6 +50,7 @@ import mage.client.chat.ChatPanelBasic; import mage.client.components.*; import mage.client.components.ext.dlg.DialogManager; import mage.client.components.tray.MageTray; +import mage.client.constants.Constants; import mage.client.constants.Constants.DeckEditorMode; import mage.client.deckeditor.DeckEditorPane; import mage.client.deckeditor.collection.viewer.CollectionViewerPane; @@ -92,8 +93,6 @@ import org.mage.plugins.card.images.DownloadPictures; import org.mage.plugins.card.info.CardInfoPaneImpl; import org.mage.plugins.card.utils.impl.ImageManagerImpl; -import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; - /** * @author BetaSteward_at_googlemail.com */ @@ -285,6 +284,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { balloonTip.setPositioner(new LeftAbovePositioner(0, 0)); balloonTip.setVisible(false); + // tooltips delay in ms + ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS); + mageToolbar.add(createSwitchPanelsButton(), 0); mageToolbar.add(new javax.swing.JToolBar.Separator(), 1); diff --git a/Mage.Client/src/main/java/mage/client/constants/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java index b1de743dc28..5547517a859 100644 --- a/Mage.Client/src/main/java/mage/client/constants/Constants.java +++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java @@ -69,6 +69,9 @@ public final class Constants { public static final int POWBOX_TEXT_MAX_LEFT = 212; public static final int DAMAGE_MAX_LEFT = 180; + // tooltip hints delay in ms (need more time to display long hints withour hiding) + public static final int TOOLTIPS_DELAY_MS = 60 * 1000; + public static final Border EMPTY_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2); public static final double SCALE_FACTOR = 0.5; diff --git a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java index d801a15d3a9..15bc6528665 100644 --- a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java @@ -51,7 +51,9 @@ import javax.swing.UIManager; import mage.client.SessionHandler; import mage.client.components.MageTextArea; +import mage.client.constants.Constants; import mage.client.game.FeedbackPanel.FeedbackMode; + import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION; import mage.client.util.GUISizeHelper; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO; @@ -82,7 +84,6 @@ public class HelperPanel extends JPanel { private javax.swing.JButton linkSpecial; private javax.swing.JButton linkUndo; - private final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay(); private final Object tooltipBackground = UIManager.get("info"); private static final String CMD_AUTO_ANSWER_ID_YES = "cmdAutoAnswerIdYes"; @@ -232,13 +233,13 @@ public class HelperPanel extends JPanel { @Override public void mouseEntered(MouseEvent me) { - ToolTipManager.sharedInstance().setDismissDelay(100000); + ToolTipManager.sharedInstance().setDismissDelay(100 * 1000); UIManager.put("info", Color.DARK_GRAY); } @Override public void mouseExited(MouseEvent me) { - ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout); + ToolTipManager.sharedInstance().setDismissDelay(Constants.TOOLTIPS_DELAY_MS); UIManager.put("info", tooltipBackground); } }); From b876b011a5aee78cb4bcef6daea148979e69b6ef Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 00:41:03 +0100 Subject: [PATCH 16/54] (Re)added missing ability --- Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java index 19cb73f7745..ad1ea1a443b 100644 --- a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java +++ b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java @@ -72,6 +72,7 @@ public class DaughterOfAutumn extends CardImpl { // {W}: The next 1 damage that would be dealt to target white creature this turn is dealt to Daughter of Autumn instead. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DaughterOfAutumnPreventDamageTargetEffect(Duration.EndOfTurn, 1), new ManaCostsImpl("{W}")); ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); } public DaughterOfAutumn(final DaughterOfAutumn card) { From a6774cdc740c78ceb79bfedf7e24c04711561076 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:45:16 +0100 Subject: [PATCH 17/54] Implemented Apocalypse Chime --- .../src/mage/cards/a/ApocalypseChime.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ApocalypseChime.java diff --git a/Mage.Sets/src/mage/cards/a/ApocalypseChime.java b/Mage.Sets/src/mage/cards/a/ApocalypseChime.java new file mode 100644 index 00000000000..8f628925461 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ApocalypseChime.java @@ -0,0 +1,79 @@ +/* + * 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.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.ExpansionSetPredicate; +import mage.filter.predicate.permanent.TokenPredicate; + +/** + * + * @author L_J + */ +public class ApocalypseChime extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("nontoken permanents with a name originally printed in the Homelands expansion"); + + static { + filter.add(Predicates.and( + Predicates.not(new TokenPredicate()), + new ExpansionSetPredicate("HML") + )); + } + + public ApocalypseChime(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {2}, {T}, Sacrifice Apocalypse Chime: Destroy all nontoken permanents with a name originally printed in the Homelands expansion. They can't be regenerated. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyAllEffect(filter, true), new ManaCostsImpl("{2}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public ApocalypseChime(final ApocalypseChime card) { + super(card); + } + + @Override + public ApocalypseChime copy() { + return new ApocalypseChime(this); + } +} From aa10e2d3365e4d4f1c31117c7179a925995167b0 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:46:33 +0100 Subject: [PATCH 18/54] Implemented Autumn Willow --- Mage/src/main/java/mage/constants/AsThoughEffectType.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage/src/main/java/mage/constants/AsThoughEffectType.java b/Mage/src/main/java/mage/constants/AsThoughEffectType.java index af2e4bf30f6..50f7caeb4f8 100644 --- a/Mage/src/main/java/mage/constants/AsThoughEffectType.java +++ b/Mage/src/main/java/mage/constants/AsThoughEffectType.java @@ -17,6 +17,7 @@ public enum AsThoughEffectType { CAST_AS_INSTANT, ACTIVATE_AS_INSTANT, DAMAGE, + SHROUD, HEXPROOF, PAY, LOOK_AT_FACE_DOWN, From bde116e201cc4f31d76bdd91a171924c03a868c2 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:48:06 +0100 Subject: [PATCH 19/54] Implemented Autumn Willow --- Mage/src/main/java/mage/game/permanent/PermanentImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 95c27b3c634..3859322d336 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -946,7 +946,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) { if (source != null) { if (abilities.containsKey(ShroudAbility.getInstance().getId())) { - return false; + if (!game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) { + return false; + } } if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) From 404c79efb1ab3a9bb7df684af88c2a27b30b7c93 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:48:49 +0100 Subject: [PATCH 20/54] Implemented Autumn Willow --- Mage.Sets/src/mage/cards/a/AutumnWillow.java | 118 +++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AutumnWillow.java diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java new file mode 100644 index 00000000000..3a090ba7ac8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -0,0 +1,118 @@ +/* + * 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.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; + +/** + * Gatecrash FAQ 21.01.2013 + * + * Creatures your opponents control don't actually lose hexproof, although you + * will ignore hexproof for purposes of choosing targets of spells and abilities + * you control. + * + * Creatures that come under your control after Glaring Spotlight's last ability + * resolves won't have hexproof but can't be blocked that turn. + * + * @author L_J + */ +public class AutumnWillow extends CardImpl { + + public AutumnWillow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Shroud + this.addAbility(ShroudAbility.getInstance()); + + // {G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AutumnWillowEffect(), new ManaCostsImpl("{G}")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public AutumnWillow(final AutumnWillow card) { + super(card); + } + + @Override + public AutumnWillow copy() { + return new AutumnWillow(this); + } +} + +class AutumnWillowEffect extends AsThoughEffectImpl { + + public AutumnWillowEffect() { + super(AsThoughEffectType.SHROUD, Duration.EndOfTurn, Outcome.Benefit); + staticText = "Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud"; + } + + public AutumnWillowEffect(final AutumnWillowEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AutumnWillowEffect copy() { + return new AutumnWillowEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (affectedControllerId.equals(source.getFirstTarget())) { + Permanent creature = game.getPermanent(sourceId); + if (creature != null) { + if (sourceId == source.getSourceId()) { + return true; + } + } + } + return false; + } +} From 5681c945a9fbeb7c521d74efb06f4bab8298f376 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:50:41 +0100 Subject: [PATCH 21/54] Removed comment --- Mage.Sets/src/mage/cards/a/AutumnWillow.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java index 3a090ba7ac8..16829e0c7d9 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnWillow.java +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -43,14 +43,6 @@ import mage.game.permanent.Permanent; import mage.target.TargetPlayer; /** - * Gatecrash FAQ 21.01.2013 - * - * Creatures your opponents control don't actually lose hexproof, although you - * will ignore hexproof for purposes of choosing targets of spells and abilities - * you control. - * - * Creatures that come under your control after Glaring Spotlight's last ability - * resolves won't have hexproof but can't be blocked that turn. * * @author L_J */ From 497ebebc05c8cc4e74093f6c2df5849b6d68d4d7 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:52:47 +0100 Subject: [PATCH 22/54] Implemented Broken Visage --- .../token/BrokenVisageSpiritToken.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java diff --git a/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java new file mode 100644 index 00000000000..9108b920c50 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java @@ -0,0 +1,52 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com AS IS AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; + +/** + * + * @author spjspj & L_J + */ +public class BrokenVisageSpiritToken extends Token { + + public BrokenVisageSpiritToken() { + this(0,0); + } + + public BrokenVisageSpiritToken(int tokenPower, int tokenToughness) { + super("Spirit", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Spirit creature token").toString()); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.SPIRIT); + power = new MageInt(tokenPower); + toughness = new MageInt(tokenToughness); + } +} From 82d4ddd0fa9336918678316e6d54754c161f3d99 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:53:38 +0100 Subject: [PATCH 23/54] Broken Visage --- Mage.Sets/src/mage/cards/b/BrokenVisage.java | 117 +++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BrokenVisage.java diff --git a/Mage.Sets/src/mage/cards/b/BrokenVisage.java b/Mage.Sets/src/mage/cards/b/BrokenVisage.java new file mode 100644 index 00000000000..9b9651b0b8d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokenVisage.java @@ -0,0 +1,117 @@ +/* + * 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.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.BrokenVisageSpiritToken; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class BrokenVisage extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact attacking creature"); + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); + filter.add(new AttackingPredicate()); + } + + public BrokenVisage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); + + // Destroy target nonartifact attacking creature. It can't be regenerated. Create a black Spirit creature token. Its power is equal to that creature's power and its toughness is equal to that creature's toughness. Sacrifice the token at the beginning of the next end step. + this.getSpellAbility().addEffect(new BrokenVisageEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public BrokenVisage(final BrokenVisage card) { + super(card); + } + + @Override + public BrokenVisage copy() { + return new BrokenVisage(this); + } +} + +class BrokenVisageEffect extends OneShotEffect { + + public BrokenVisageEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Destroy target nonartifact attacking creature. It can't be regenerated. Create a black Spirit creature token. Its power is equal to that creature's power and its toughness is equal to that creature's toughness. Sacrifice the token at the beginning of the next end step"; + } + + public BrokenVisageEffect(final BrokenVisageEffect effect) { + super(effect); + } + + @Override + public BrokenVisageEffect copy() { + return new BrokenVisageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, true); + CreateTokenEffect effect = new CreateTokenEffect(new BrokenVisageSpiritToken(permanent.getPower().getValue(), permanent.getToughness().getValue())); + effect.apply(game, source); + for (UUID tokenId : effect.getLastAddedTokenIds()) { + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("Sacrifice the token at the beginning of the next end step", source.getControllerId()); + sacrificeEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + } + } + return true; + } + +} From ea29eb5a85457b9d6228241a4db2b05f9e0b128d Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:54:29 +0100 Subject: [PATCH 24/54] Hazduhr the Abbot --- .../src/mage/cards/h/HazduhrTheAbbot.java | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java diff --git a/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java new file mode 100644 index 00000000000..bbe55f549fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java @@ -0,0 +1,130 @@ +/* + * 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.h; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +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.RedirectionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author TheElk801 & L_J + */ +public class HazduhrTheAbbot extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("white creature you control"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public HazduhrTheAbbot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // {X}, {T}: The next X damage that would be dealt this turn to target white creature you control is dealt to Hazduhr the Abbot instead. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HazduhrTheAbbotRedirectDamageEffect(Duration.EndOfTurn), new ManaCostsImpl("{X}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent(filter)); + this.addAbility(ability); + } + + public HazduhrTheAbbot(final HazduhrTheAbbot card) { + super(card); + } + + @Override + public HazduhrTheAbbot copy() { + return new HazduhrTheAbbot(this); + } +} + +class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect { + + private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + public HazduhrTheAbbotRedirectDamageEffect(Duration duration) { + super(duration, 0, true); + this.staticText = "The next X damage that would be dealt this turn to target white creature you control is dealt to {this} instead"; + } + + public HazduhrTheAbbotRedirectDamageEffect(final HazduhrTheAbbotRedirectDamageEffect effect) { + super(effect); + } + + @Override + public void init(Ability source, Game game) { + amountToRedirect = source.getManaCostsToPay().getX(); + } + + @Override + public HazduhrTheAbbotRedirectDamageEffect copy() { + return new HazduhrTheAbbotRedirectDamageEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); + if (permanent != null) { + if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { + if (event.getTargetId() != null) { + TargetPermanent target = new TargetPermanent(); + target.add(source.getSourceId(), game); + redirectTarget = target; + return true; + } + } + } + } + return false; + } +} From 98cab3a0b72d8a5ff9893ac46004dd3610424128 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:55:32 +0100 Subject: [PATCH 25/54] Implemented Joven's Tools --- Mage.Sets/src/mage/cards/j/JovensTools.java | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/j/JovensTools.java diff --git a/Mage.Sets/src/mage/cards/j/JovensTools.java b/Mage.Sets/src/mage/cards/j/JovensTools.java new file mode 100644 index 00000000000..642ece28ae4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JovensTools.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.cards.j; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public class JovensTools extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("except by walls"); + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); + } + + public JovensTools(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + + // {4}, {T}: Target creature can't be blocked this turn except by Walls. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public JovensTools(final JovensTools card) { + super(card); + } + + @Override + public JovensTools copy() { + return new JovensTools(this); + } +} From bc3e647544c98ee8569d2e6af4523eade001b111 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:56:13 +0100 Subject: [PATCH 26/54] Implemented Mammoth Harness --- .../src/mage/cards/m/MammothHarness.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MammothHarness.java diff --git a/Mage.Sets/src/mage/cards/m/MammothHarness.java b/Mage.Sets/src/mage/cards/m/MammothHarness.java new file mode 100644 index 00000000000..d17c63e4d9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MammothHarness.java @@ -0,0 +1,135 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public class MammothHarness extends CardImpl { + + public MammothHarness(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.LoseAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature loses flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LoseAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + + // Whenever enchanted creature blocks or becomes blocked by a creature, the other creature gains first strike until end of turn. + this.addAbility(new MammothHarnessTriggeredAbility()); + } + + public MammothHarness(final MammothHarness card) { + super(card); + } + + @Override + public MammothHarness copy() { + return new MammothHarness(this); + } +} + +class MammothHarnessTriggeredAbility extends BlocksOrBecomesBlockedTriggeredAbility { + + public MammothHarnessTriggeredAbility() { + super(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_PERMANENT_CREATURE, false, null, false); + } + + public MammothHarnessTriggeredAbility(final MammothHarnessTriggeredAbility ability) { + super(ability); + + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(this.getSourceId()); + if (sourcePermanent != null) { + Permanent attachedTo = game.getPermanentOrLKIBattlefield(sourcePermanent.getAttachedTo()); + if (sourcePermanent != null) { + if (event.getSourceId().equals(attachedTo.getId())) { + Permanent blocked = game.getPermanent(event.getTargetId()); + if (blocked != null && filter.match(blocked, game)) { + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + } + if (event.getTargetId().equals(attachedTo.getId())) { + Permanent blocker = game.getPermanent(event.getSourceId()); + if (blocker != null) { + this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId())); + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return " Whenever enchanted creature blocks or becomes blocked by a creature, the other creature gains first strike until end of turn."; + } + + @Override + public MammothHarnessTriggeredAbility copy() { + return new MammothHarnessTriggeredAbility(this); + } +} From a9a2f85c4c095e5a79159dc3841d7d6681a9c855 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:57:10 +0100 Subject: [PATCH 27/54] Implemented Rashka the Slayer --- .../src/mage/cards/r/RashkaTheSlayer.java | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RashkaTheSlayer.java diff --git a/Mage.Sets/src/mage/cards/r/RashkaTheSlayer.java b/Mage.Sets/src/mage/cards/r/RashkaTheSlayer.java new file mode 100644 index 00000000000..e9d4a65cdea --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RashkaTheSlayer.java @@ -0,0 +1,127 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author L_J + */ +public class RashkaTheSlayer extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public RashkaTheSlayer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARCHER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever Rashka the Slayer blocks one or more black creatures, Rashka gets +1/+2 until end of turn. + this.addAbility(new RashkaTheSlayerTriggeredAbility(new BoostSourceEffect(1, 2, Duration.EndOfTurn), filter, false)); + } + + public RashkaTheSlayer(final RashkaTheSlayer card) { + super(card); + } + + @Override + public RashkaTheSlayer copy() { + return new RashkaTheSlayer(this); + } +} + +class RashkaTheSlayerTriggeredAbility extends TriggeredAbilityImpl { + + protected FilterPermanent filter; + + public RashkaTheSlayerTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) { + super(Zone.BATTLEFIELD, effect, optional); + this.filter = filter; + } + + public RashkaTheSlayerTriggeredAbility(final RashkaTheSlayerTriggeredAbility 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 RashkaTheSlayerTriggeredAbility copy() { + return new RashkaTheSlayerTriggeredAbility(this); + } +} From ff92c0c78a1aa1bc13b0766268ec48186474c189 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:58:05 +0100 Subject: [PATCH 28/54] Implemented cards --- Mage.Sets/src/mage/sets/Homelands.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Mage.Sets/src/mage/sets/Homelands.java b/Mage.Sets/src/mage/sets/Homelands.java index 6113b95dca7..2a5cb439a87 100644 --- a/Mage.Sets/src/mage/sets/Homelands.java +++ b/Mage.Sets/src/mage/sets/Homelands.java @@ -83,6 +83,8 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("An-Havva Inn", 52, Rarity.UNCOMMON, mage.cards.a.AnHavvaInn.class)); cards.add(new SetCardInfo("An-Havva Township", 136, Rarity.UNCOMMON, mage.cards.a.AnHavvaTownship.class)); cards.add(new SetCardInfo("An-Zerrin Ruins", 87, Rarity.RARE, mage.cards.a.AnZerrinRuins.class)); + cards.add(new SetCardInfo("Apocalypse Chime", 126, Rarity.RARE, mage.cards.a.ApocalypseChime.class)); + cards.add(new SetCardInfo("Autumn Willow", 53, Rarity.RARE, mage.cards.a.AutumnWillow.class)); cards.add(new SetCardInfo("Aysen Abbey", 137, Rarity.UNCOMMON, mage.cards.a.AysenAbbey.class)); cards.add(new SetCardInfo("Aysen Bureaucrats", 104, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aysen Bureaucrats", 105, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class, NON_FULL_USE_VARIOUS)); @@ -91,6 +93,7 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Baki's Curse", 27, Rarity.RARE, mage.cards.b.BakisCurse.class)); cards.add(new SetCardInfo("Baron Sengir", 1, Rarity.RARE, mage.cards.b.BaronSengir.class)); cards.add(new SetCardInfo("Black Carriage", 2, Rarity.RARE, mage.cards.b.BlackCarriage.class)); + cards.add(new SetCardInfo("Broken Visage", 3, Rarity.RARE, mage.cards.b.BrokenVisage.class)); cards.add(new SetCardInfo("Carapace", 54, Rarity.COMMON, mage.cards.c.Carapace.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carapace", 55, Rarity.COMMON, mage.cards.c.Carapace.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Castle Sengir", 138, Rarity.UNCOMMON, mage.cards.c.CastleSengir.class)); @@ -124,6 +127,7 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Forget", 32, Rarity.RARE, mage.cards.f.Forget.class)); cards.add(new SetCardInfo("Ghost Hounds", 12, Rarity.UNCOMMON, mage.cards.g.GhostHounds.class)); cards.add(new SetCardInfo("Grandmother Sengir", 13, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); + cards.add(new SetCardInfo("Hazduhr the Abbot", 110, Rarity.RARE, mage.cards.h.HazduhrTheAbbot.class)); cards.add(new SetCardInfo("Headstone", 15, Rarity.COMMON, mage.cards.h.Headstone.class)); cards.add(new SetCardInfo("Hungry Mist", 60, Rarity.COMMON, mage.cards.h.HungryMist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hungry Mist", 61, Rarity.COMMON, mage.cards.h.HungryMist.class, NON_FULL_USE_VARIOUS)); @@ -131,11 +135,13 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Irini Sengir", 17, Rarity.UNCOMMON, mage.cards.i.IriniSengir.class)); cards.add(new SetCardInfo("Jinx", 36, Rarity.COMMON, mage.cards.j.Jinx.class)); cards.add(new SetCardInfo("Joven", 97, Rarity.COMMON, mage.cards.j.Joven.class)); + cards.add(new SetCardInfo("Joven's Tools", 133, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); cards.add(new SetCardInfo("Koskun Falls", 18, Rarity.RARE, mage.cards.k.KoskunFalls.class)); cards.add(new SetCardInfo("Koskun Keep", 139, Rarity.UNCOMMON, mage.cards.k.KoskunKeep.class)); cards.add(new SetCardInfo("Labyrinth Minotaur", 38, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); cards.add(new SetCardInfo("Leaping Lizard", 63, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); cards.add(new SetCardInfo("Leeches", 111, Rarity.RARE, mage.cards.l.Leeches.class)); + cards.add(new SetCardInfo("Mammoth Harness", 64, Rarity.RARE, mage.cards.m.MammothHarness.class)); cards.add(new SetCardInfo("Marjhan", 39, Rarity.RARE, mage.cards.m.Marjhan.class)); cards.add(new SetCardInfo("Memory Lapse", 40, Rarity.COMMON, mage.cards.m.MemoryLapse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Memory Lapse", 41, Rarity.COMMON, mage.cards.m.MemoryLapse.class, NON_FULL_USE_VARIOUS)); @@ -145,6 +151,7 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Mystic Decree", 43, Rarity.RARE, mage.cards.m.MysticDecree.class)); cards.add(new SetCardInfo("Narwhal", 44, Rarity.RARE, mage.cards.n.Narwhal.class)); cards.add(new SetCardInfo("Primal Order", 65, Rarity.RARE, mage.cards.p.PrimalOrder.class)); + cards.add(new SetCardInfo("Rashka the Slayer", 115, Rarity.RARE, mage.cards.r.RashkaTheSlayer.class)); cards.add(new SetCardInfo("Reef Pirates", 45, Rarity.COMMON, ReefPirates.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reef Pirates", 46, Rarity.COMMON, ReefPirates.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Renewal", 66, Rarity.COMMON, mage.cards.r.Renewal.class)); From a06f6244a7b8f84f924d77362b9e5353e185de49 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:58:31 +0100 Subject: [PATCH 29/54] Implemented cards --- Mage.Sets/src/mage/sets/MastersEditionII.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index ec1bba35f8f..5d6f806cd9a 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -93,6 +93,7 @@ public class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, BrassclawOrcs.class)); cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class)); cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class)); + cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class)); cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class)); cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class)); From d4588fbf48166403bc93bc7103efda2485e6a914 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:58:58 +0100 Subject: [PATCH 30/54] Implemented cards --- Mage.Sets/src/mage/sets/MastersEdition.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/MastersEdition.java b/Mage.Sets/src/mage/sets/MastersEdition.java index eb9d2ee2936..c0c6451fead 100644 --- a/Mage.Sets/src/mage/sets/MastersEdition.java +++ b/Mage.Sets/src/mage/sets/MastersEdition.java @@ -76,6 +76,7 @@ public class MastersEdition extends ExpansionSet { cards.add(new SetCardInfo("Armageddon", 4, Rarity.RARE, mage.cards.a.Armageddon.class)); cards.add(new SetCardInfo("Artifact Blast", 85, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); cards.add(new SetCardInfo("Ashnod's Transmogrant", 152, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); + cards.add(new SetCardInfo("Autumn Willow", 113, Rarity.RARE, mage.cards.a.AutumnWillow.class)); cards.add(new SetCardInfo("Balduvian Horde", 86, Rarity.RARE, mage.cards.b.BalduvianHorde.class)); cards.add(new SetCardInfo("Ball Lightning", 87, Rarity.RARE, mage.cards.b.BallLightning.class)); cards.add(new SetCardInfo("Baron Sengir", 58, Rarity.RARE, mage.cards.b.BaronSengir.class)); From d2fdc26ef1c7abb2aa73080b15c17b449a271e89 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 05:59:36 +0100 Subject: [PATCH 31/54] Implemented cards --- Mage.Sets/src/mage/sets/FifthEdition.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index 23672aa5d01..1afb371eef6 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -80,6 +80,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Brainwash", 289, Rarity.COMMON, mage.cards.b.Brainwash.class)); cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, BrassclawOrcs.class)); cards.add(new SetCardInfo("Breeding Pit", 10, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); + cards.add(new SetCardInfo("Broken Visage", 11, Rarity.RARE, mage.cards.b.BrokenVisage.class)); cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class)); cards.add(new SetCardInfo("Carapace", 143, Rarity.COMMON, mage.cards.c.Carapace.class)); @@ -242,6 +243,7 @@ public class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class)); cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); cards.add(new SetCardInfo("Justice", 317, Rarity.UNCOMMON, mage.cards.j.Justice.class)); cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class)); cards.add(new SetCardInfo("Karma", 318, Rarity.UNCOMMON, mage.cards.k.Karma.class)); From 8d0079bd3da1fd897d3ed1f4798d10dc5451994c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 15:00:27 +0100 Subject: [PATCH 32/54] [RIX] Updated mtg-cards-data.txt with spoilers of 2018-01-02 15:00 CET --- Utils/mtg-cards-data.txt | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 2013cd36113..091ab4951c1 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -32696,15 +32696,39 @@ Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G} to yo Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to target creature or player, where X is the number of Gremlins you control.| Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)| Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.| +Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to it's toughness.| +Glorious Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$As Glorious Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.| +Shrine Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source would deal damage to another Dinosaur you control, prevent all but 1 of that damage.| +Zetalpa, Primal Dawn|Rivals of Ixalan|30|R|{6}{W}{W}|Legendary Creature - Elder Dinosaur|4|8|Flying, double strike, vigilance, trample, indestructible| +River Darter|Rivals of Ixalan|47|C|{2}{U}|Creature - Merfolk Warrior|2|3|River Darter can't be blocked by Dinosaurs.| +Seafloor Oracle|Rivals of Ixalan|51|R|{2}{W}{W}|Creature - Merfolk Wizard|2|3|Whenever a Merfolk you controls deals combat damage to a player, draw a card.| +Secrets of the Golden City|Rivals of Ixalan|52|C|{1}{U}{U}|Sorcery|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Draw two cards. If you have the city's blessing, draw three cards instead.| Silvergill Adept|Rivals of Ixalan|53|U|{1}{U}|Creature - Merfolk Wizard|2|1|As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.$When Silvergill Adept enters the battlefield, draw a card.| +Dusk Charger|Rivals of Ixalan|69|C|{3}{B}|Creature - Horse|3|3|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Dusk Charger gets +2/+2 as long as you have the city's blessing.| Tetzimoc, Primal Death|Rivals of Ixalan|86|R|{4}{B}{B}|Legendary Creature - Elder Dinosaur|6|6|Deathtouch${B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.$When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it.| Vona's Hunger|Rivals of Ixalan|90|R|{2}{B}|Instant|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Each opponent sacrifices a creature. If you have the city's blessing, instead each opponent sacrifices half the creatures he or she controls rounded up.| Brass's Bounty|Rivals of Ixalan|94|R|{6}{R}|Sorcery|||For each land you control, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| +Form of the Dinosaur|Rivals of Ixalan|103|R|{4}{R}{R}|Enchantment|||When Form of the Dinosaur enters the battlefield, your life total becomes 15.$At the beginning of your upkeep, Form of the Dinosaur deals 15 damage to target creature an opponent controls and that creature deals damage equal to its power to you.| +Frilled Deathspitter|Rivals of Ixalan|104|C|{2}{R}|Creature - Dinosaur|3|2|Enrage — Whenever Frilled Deathspitter is dealt damage, it deals 2 damage to target opponent.| +Swaggering Corsair|Rivals of Ixalan|119|C|{2}{R}|Creature - Human Pirate|2|2|Raid — Swaggering Corsair enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn.| +Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step, unless you have the City's blessing.| +Enter the Unknown|Rivals of Ixalan|128|U|{G}|Sorcery|||Target creature you control explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.) $You may play an additional land this turn.| Ghalta, Primal Hunger|Rivals of Ixalan|130|R|{1}{0}{G}{G}|Legendary Creature - Elder Dinosaur|12|12|Ghalta, Primal Hunger costs {X} less to cast, where X is the total power of creatures you control.$Trample| +Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)| +Tendershoot Dryad|Rivals of Ixalan|147|R|{4}{G}|Creature - Dryad|2|2|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$At the beginning of each upkeep, create a 1/1 green Saproling creature token.$Saprolings you control get +2/+2 as long as you have the city's blessing.| +Thrashing Brontodon|Rivals of Ixalan|148|U|{1}{G}{G}|Creature - Dinosaur|3|4|{1}, Sacrificing Thrashing Brontodon: Destroy target artifact or enchantment.| +Angrath, the Flame-Chained|Rivals of Ixalan|152|M|{3}{B}{R}|Legendary Planeswalker - Angrath|4|+1: Each opponent discards a card and loses 2 life.$-3: Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. Sacrifice it at the beginning of the next end step if it has converted mana cost 3 or less.$-8: Each opponent loses life equal to the number of cards in his or her graveyard.| +Atzocan Seer|Rivals of Ixalan|153|U|{1}{G}{W}|Creature - Human Druid|2|3|{t}: Add one mana of any color to your manan pool.$Sacrifice Atzocan Seer: Return target Dinosaur card from your graveyard to your hand.| +Elenda, the Dusk Rose|Rivals of Ixalan|157|M|{2}{W}{B}|Legendary Creature - Vampire Knight|1|1|Lifelink$Whenever another creature dies, put a +1/+1 counter on Elenda, the Dusk Rose.$When Elenda dies, create X 1/1 white Vampire creature tokens with lifelink, where X is Elenda's power| +Journey to Eternity|Rivals of Ixalan|160|R|{1}{B}{G}|Legendary Enchantment - Aura|||Enchant creature you control$When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control.| +Atzal, Cave of Eternity|Rivals of Ixalan|160|R||Legendary Land|||(Transforms from Journey to Eternity.)${t}: Add one mana of any color to your mana pool.${3}{B}{G}, {t}: Return target creature card from your graveyard to the battlefield.| +Kumena, Tyrant of Orzca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| Storm the Vault|Rivals of Ixalan|173|R|{2}{U}{R}|Legendary Enchantment|||Whenever one or more creatures you control deal combat damage to a player, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool."$At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault.| Vault of Catlacan|Rivals of Ixalan|173|R||Legendary Land|||(Transforms from Storm the Vault.)${T}: Add one mana of any color to your mana pool.${T}: Add {U} to your mana pool for each artifact you control.| +Awakened Amalgamation|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgamation's power and toughness are each equal to the number of lands you control with different names.| Captain's Hook|Rivals of Ixalan|177|R|{3}|Artifact - Equipment|||Equipped creature gets +2/+0, has menace, and is a Pirate in addition to its other creature types.$Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent.$Equip {1}| -The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate loyalty abilities of planeswalkers.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.| +Gleaming Barrier|Rivals of Ixalan|178|C|{2}|Artifact Creature - Wall|0|4|Defender$When Gleaming Barrier dies, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| +The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate planeswalkers' loyalty abilities.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.| Evolving Wilds|Rivals of Ixalan|186|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| Vraska, Scheming Gorgon|Rivals of Ixalan|197|M|{4}{B}{B}|Legendary Planeswalker - Vraska|5|+2: Creatures you control get +1/+0 until end of turn.$-3: Destroy target creature.$-10: Until end of turn, creatures you control gain deathtouch and "Whenever this creature deals damage to an opponent, that player loses the game."| Vampire Champion|Rivals of Ixalan|198|C|{3}{B}|Creature - Vampire Soldier|3|3|Deathtouch (Any amount of damage this deals to a creature is enough to destroy it.)| From 70c08a2d810565a59b98831a47f22fe78da928a8 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 15:01:58 +0100 Subject: [PATCH 33/54] * Victimize - Fixed that continuous effects of sacrificed permanent did not end before returning targets from graveyard (fixes #4315). --- Mage.Sets/src/mage/cards/v/Victimize.java | 3 ++- .../java/mage/abilities/effects/common/DoIfCostPaid.java | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/cards/v/Victimize.java b/Mage.Sets/src/mage/cards/v/Victimize.java index 509f29e36f1..5ff6e591e1f 100644 --- a/Mage.Sets/src/mage/cards/v/Victimize.java +++ b/Mage.Sets/src/mage/cards/v/Victimize.java @@ -51,7 +51,7 @@ import mage.target.common.TargetControlledCreaturePermanent; public class Victimize extends CardImpl { public Victimize(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Choose two target creature cards in your graveyard. Sacrifice a creature. If you do, return the chosen cards to the battlefield tapped. this.getSpellAbility().addEffect(new VictimizeEffect()); @@ -90,6 +90,7 @@ class VictimizeEffect extends OneShotEffect { if (controller != null) { SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature"))); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { + game.applyEffects(); // To end effects of the sacrificed creature controller.moveCards(new CardsImpl(getTargetPointer().getTargets(game, source)).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java index 75f36ec46ca..c264b34e9d9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java @@ -77,6 +77,7 @@ public class DoIfCostPaid extends OneShotEffect { && (!optional || player.chooseUse(executingEffects.get(0).getOutcome(), message, source, game))) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + game.applyEffects(); // To end effects e.g. of sacrificed permanents for (Effect effect : executingEffects) { effect.setTargetPointer(this.targetPointer); if (effect instanceof OneShotEffect) { @@ -86,8 +87,7 @@ public class DoIfCostPaid extends OneShotEffect { } } player.resetStoredBookmark(game); // otherwise you can e.g. undo card drawn with Mentor of the Meek - } - else if (!otherwiseEffects.isEmpty()) { + } else if (!otherwiseEffects.isEmpty()) { for (Effect effect : otherwiseEffects) { effect.setTargetPointer(this.targetPointer); if (effect instanceof OneShotEffect) { @@ -97,8 +97,7 @@ public class DoIfCostPaid extends OneShotEffect { } } } - } - else if (!otherwiseEffects.isEmpty()) { + } else if (!otherwiseEffects.isEmpty()) { for (Effect effect : otherwiseEffects) { effect.setTargetPointer(this.targetPointer); if (effect instanceof OneShotEffect) { From 050a70b7dbbfd1ec6af14854ffad92847480492c Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 2 Jan 2018 19:38:08 +0400 Subject: [PATCH 34/54] UI: fixed #4329 - errors on card selection in linux (debian) --- .../card/arcane/ManaSymbolsCellRenderer.java | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java index 1de0abceb11..46a0e3f1c2c 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java @@ -35,28 +35,30 @@ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer { String manaCost = (String)value; manaPanel.removeAll(); manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS)); - StringTokenizer tok = new StringTokenizer(manaCost, " "); - while (tok.hasMoreTokens()) { - String symbol = tok.nextToken(); + if(manaCost != null){ + StringTokenizer tok = new StringTokenizer(manaCost, " "); + while (tok.hasMoreTokens()) { + String symbol = tok.nextToken(); - JLabel symbolLabel = new JLabel(); - //symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug - symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0)); + JLabel symbolLabel = new JLabel(); + //symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug + symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0)); - BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth); - if (image != null){ - // icon - symbolLabel.setIcon(new ImageIcon(image)); - }else - { - // text - symbolLabel.setText("{" + symbol + "}"); - symbolLabel.setOpaque(baseLabel.isOpaque()); - symbolLabel.setForeground(baseLabel.getForeground()); - symbolLabel.setBackground(baseLabel.getBackground()); + BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth); + if (image != null){ + // icon + symbolLabel.setIcon(new ImageIcon(image)); + }else + { + // text + symbolLabel.setText("{" + symbol + "}"); + symbolLabel.setOpaque(baseLabel.isOpaque()); + symbolLabel.setForeground(baseLabel.getForeground()); + symbolLabel.setBackground(baseLabel.getBackground()); + } + + manaPanel.add(symbolLabel); } - - manaPanel.add(symbolLabel); } return manaPanel; From 988076b93c1e8aacae4077a53d2735b5dd83fd97 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 16:44:31 +0100 Subject: [PATCH 35/54] Minor fix --- Mage.Sets/src/mage/cards/a/AutumnWillow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java index 16829e0c7d9..7ccb1202e4a 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnWillow.java +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -100,7 +100,7 @@ class AutumnWillowEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getFirstTarget())) { Permanent creature = game.getPermanent(sourceId); if (creature != null) { - if (sourceId == source.getSourceId()) { + if (sourceId.equals(source.getSourceId())) { return true; } } From 30482ff1aee246921c311e3463778831faf9e016 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 16:59:50 +0100 Subject: [PATCH 36/54] Implemented Zetalpa, Primal Dawn --- .../src/mage/cards/z/ZetalpaPrimalDawn.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/z/ZetalpaPrimalDawn.java diff --git a/Mage.Sets/src/mage/cards/z/ZetalpaPrimalDawn.java b/Mage.Sets/src/mage/cards/z/ZetalpaPrimalDawn.java new file mode 100644 index 00000000000..3115fe269b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZetalpaPrimalDawn.java @@ -0,0 +1,78 @@ +/* + * 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.z; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +/** + * + * @author L_J + */ +public class ZetalpaPrimalDawn extends CardImpl { + + public ZetalpaPrimalDawn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{W}{W}"); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELDER); + this.subtype.add(SubType.DINOSAUR); + + this.power = new MageInt(4); + this.toughness = new MageInt(8); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + // Trample + this.addAbility(TrampleAbility.getInstance()); + // Indestructible + this.addAbility(IndestructibleAbility.getInstance()); + } + + public ZetalpaPrimalDawn(final ZetalpaPrimalDawn card) { + super(card); + } + + @Override + public ZetalpaPrimalDawn copy() { + return new ZetalpaPrimalDawn(this); + } +} From 40578b10bf02ea6f309eba98302bb4dc9bb882e2 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 17:01:31 +0100 Subject: [PATCH 37/54] Implemented Elenda, the Dusk Rose --- .../src/mage/cards/e/ElendaTheDuskRose.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/ElendaTheDuskRose.java diff --git a/Mage.Sets/src/mage/cards/e/ElendaTheDuskRose.java b/Mage.Sets/src/mage/cards/e/ElendaTheDuskRose.java new file mode 100644 index 00000000000..6fac21de271 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElendaTheDuskRose.java @@ -0,0 +1,78 @@ +/* + * 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.MageInt; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +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.game.permanent.token.IxalanVampireToken; + +/** + * + * @author L_J + */ +public class ElendaTheDuskRose extends CardImpl { + + public ElendaTheDuskRose(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever another creature dies, put a +1/+1 counter on Elenda, The Dusk Rose. + this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); + + // When Elenda dies, create X 1/1 white Vampire creature tokens with lifelink, where X is Elenda's power. + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new IxalanVampireToken(), new SourcePermanentPowerCount()))); + } + + public ElendaTheDuskRose(final ElendaTheDuskRose card) { + super(card); + } + + @Override + public ElendaTheDuskRose copy() { + return new ElendaTheDuskRose(this); + } +} From ef7e7f861d006c10a4f329f54bb47aa6be3eb9f3 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Tue, 2 Jan 2018 17:04:40 +0100 Subject: [PATCH 38/54] [RIX] Implemented 2 cards --- Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 710c3994e78..7affc67c2f3 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -61,6 +61,7 @@ public class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); @@ -74,5 +75,6 @@ public class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); } } From 7d026c699fccdcd0329fd3b98393fea9f1b58078 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 17:47:38 +0100 Subject: [PATCH 39/54] [RIX] Added 3 cards. --- Mage.Sets/src/mage/cards/a/ArdentRecruit.java | 8 +- Mage.Sets/src/mage/cards/d/DuskCharger.java | 78 +++++++++ Mage.Sets/src/mage/cards/f/FirstResponse.java | 42 +---- .../src/mage/cards/g/GloriousDestiny.java | 92 ++++++++++ .../src/mage/cards/p/PaladinOfAtonement.java | 79 +++++++++ Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 159 +++++++++--------- .../common/LiveLostLastTurnCondition.java | 54 ++++++ .../ConditionalTriggeredAbility.java | 14 +- .../effects/keyword/AscendEffect.java | 23 +-- .../mage/abilities/keyword/AscendAbility.java | 115 +++++++++++++ .../main/java/mage/filter/StaticFilters.java | 3 + .../main/java/mage/watchers/WatcherUtils.java | 46 +++++ .../common/PlayerLostLifeWatcher.java | 2 +- Utils/keywords.txt | 1 + 14 files changed, 571 insertions(+), 145 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/d/DuskCharger.java create mode 100644 Mage.Sets/src/mage/cards/g/GloriousDestiny.java create mode 100644 Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java create mode 100644 Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/AscendAbility.java create mode 100644 Mage/src/main/java/mage/watchers/WatcherUtils.java diff --git a/Mage.Sets/src/mage/cards/a/ArdentRecruit.java b/Mage.Sets/src/mage/cards/a/ArdentRecruit.java index 1fe2d66ec16..c793bb04351 100644 --- a/Mage.Sets/src/mage/cards/a/ArdentRecruit.java +++ b/Mage.Sets/src/mage/cards/a/ArdentRecruit.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.a; import java.util.UUID; @@ -46,14 +45,17 @@ import mage.constants.*; public class ArdentRecruit extends CardImpl { public ArdentRecruit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(1); this.toughness = new MageInt(1); + + // Metalcraft — Ardent Recruit gets +2/+2 as long as you control three or more artifacts. ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, "Ardent Recruit gets +2/+2 as long as you control three or more artifacts"); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, + "{this} gets +2/+2 as long as you control three or more artifacts"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.setAbilityWord(AbilityWord.METALCRAFT); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DuskCharger.java b/Mage.Sets/src/mage/cards/d/DuskCharger.java new file mode 100644 index 00000000000..e9a09ec133f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskCharger.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.AscendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class DuskCharger extends CardImpl { + + public DuskCharger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HORSE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Ascend + this.addAbility(new AscendAbility()); + + // Dusk Charger gets +2/+2 as long as you have the city's blessing. + ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, + "{this} gets +2/+2 as long as you have the city's blessing"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + this.addAbility(ability); + } + + public DuskCharger(final DuskCharger card) { + super(card); + } + + @Override + public DuskCharger copy() { + return new DuskCharger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirstResponse.java b/Mage.Sets/src/mage/cards/f/FirstResponse.java index 51b618397af..5e249cf39dd 100644 --- a/Mage.Sets/src/mage/cards/f/FirstResponse.java +++ b/Mage.Sets/src/mage/cards/f/FirstResponse.java @@ -28,18 +28,15 @@ package mage.cards.f; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.condition.common.LiveLostLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; -import mage.game.Game; import mage.game.permanent.token.SoldierToken; -import mage.watchers.common.PlayerLostLifeWatcher; /** * @@ -51,8 +48,10 @@ public class FirstResponse extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FirstResponseEffect(), TargetController.ANY, false), new PlayerLostLifeWatcher()); - + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SoldierToken()), TargetController.ANY, false), + LiveLostLastTurnCondition.instance, + "At the beginning of each upkeep, if you lost life last turn, create a 1/1 white Soldier creature token.")); } public FirstResponse(final FirstResponse card) { @@ -64,32 +63,3 @@ public class FirstResponse extends CardImpl { return new FirstResponse(this); } } - -class FirstResponseEffect extends OneShotEffect { - - public FirstResponseEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "if you lost life last turn, create a 1/1 white Soldier creature token"; - } - - public FirstResponseEffect(final FirstResponseEffect effect) { - super(effect); - } - - @Override - public FirstResponseEffect copy() { - return new FirstResponseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); - if (watcher != null) { - if (watcher.getLiveLostLastTurn(source.getControllerId()) > 0) { - return new CreateTokenEffect(new SoldierToken()).apply(game, source); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GloriousDestiny.java b/Mage.Sets/src/mage/cards/g/GloriousDestiny.java new file mode 100644 index 00000000000..ec88a4e9ef9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GloriousDestiny.java @@ -0,0 +1,92 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllOfChosenSubtypeEffect; +import mage.abilities.keyword.AscendAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LevelX2 + */ +public class GloriousDestiny extends CardImpl { + + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public GloriousDestiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Ascend + this.addAbility(new AscendAbility()); + + // As Glorious Destiny enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.BoostCreature))); + + // Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true)); + ContinuousEffect effect = new ConditionalContinuousEffect( + new GainAbilityAllOfChosenSubtypeEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, FILTER_PERMANENT_CREATURES_CONTROLLED), + CitysBlessingCondition.instance, + "They have vigilance as long as you have the city's blessing"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public GloriousDestiny(final GloriousDestiny card) { + super(card); + } + + @Override + public GloriousDestiny copy() { + return new GloriousDestiny(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java new file mode 100644 index 00000000000..941c0495abe --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PaladinOfAtonement.java @@ -0,0 +1,79 @@ +/* + * 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.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.condition.common.LiveLostLastTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentToughnessValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; + +/** + * + * @author LevelX2 + */ +public class PaladinOfAtonement extends CardImpl { + + public PaladinOfAtonement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.ANY, false), + LiveLostLastTurnCondition.instance, + "At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on {this}")); + + // When Paladin of Atonement dies, you gain life equal to it's toughness. + this.addAbility(new DiesTriggeredAbility(new GainLifeEffect(SourcePermanentToughnessValue.getInstance(), + "you gain life equal to it's toughness"))); + } + + public PaladinOfAtonement(final PaladinOfAtonement card) { + super(card); + } + + @Override + public PaladinOfAtonement copy() { + return new PaladinOfAtonement(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 710c3994e78..3aab703e2f3 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -1,78 +1,81 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author fireshoes - */ -public class RivalsOfIxalan extends ExpansionSet { - - private static final RivalsOfIxalan instance = new RivalsOfIxalan(); - - public static RivalsOfIxalan getInstance() { - return instance; - } - - private RivalsOfIxalan() { - super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); - this.blockName = "Ixalan"; - this.parentSet = Ixalan.getInstance(); - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - - cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); - cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); - cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); - cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); - cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); - cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); - cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); - cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); - cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); - cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); - cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); - cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); - cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); - cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); - cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); - cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); - } -} +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class RivalsOfIxalan extends ExpansionSet { + + private static final RivalsOfIxalan instance = new RivalsOfIxalan(); + + public static RivalsOfIxalan getInstance() { + return instance; + } + + private RivalsOfIxalan() { + super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); + this.blockName = "Ixalan"; + this.parentSet = Ixalan.getInstance(); + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); + cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); + cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); + cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); + cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); + cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); + cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); + cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java new file mode 100644 index 00000000000..61fd4c49fe2 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java @@ -0,0 +1,54 @@ +/* + * 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 mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.watchers.WatcherUtils; +import mage.watchers.common.PlayerLostLifeWatcher; + +/** + * + * @author LevelX + */ +public enum LiveLostLastTurnCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + if (watcher != null) { + return watcher.getLiveLostLastTurn(source.getControllerId()) > 0; + } else { + WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass()); + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java index 33a9dc10a78..a450227a675 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalTriggeredAbility.java @@ -19,7 +19,7 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { protected TriggeredAbility ability; protected Condition condition; - protected String text; + protected String abilityText; /** * Triggered ability with a condition. Set the optionality for the trigger @@ -27,22 +27,22 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { * * @param ability * @param condition - * @param text if null or empty, the rule text of the triggered ability - * itself is used. + * @param text explicit rule text for the ability, if null or empty, the + * rule text generated by the triggered ability itself is used. */ public ConditionalTriggeredAbility(TriggeredAbility ability, Condition condition, String text) { super(ability.getZone(), null); this.ability = ability; this.modes = ability.getModes(); this.condition = condition; - this.text = text; + this.abilityText = text; } public ConditionalTriggeredAbility(final ConditionalTriggeredAbility triggered) { super(triggered); this.ability = triggered.ability.copy(); this.condition = triggered.condition; - this.text = triggered.text; + this.abilityText = triggered.abilityText; } @Override @@ -69,10 +69,10 @@ public class ConditionalTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - if (text == null || text.isEmpty()) { + if (abilityText == null || abilityText.isEmpty()) { return ability.getRule(); } - return text; + return abilityText; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java index 11d7bbba84d..be290d6eac9 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AscendEffect.java @@ -29,12 +29,9 @@ package mage.abilities.effects.keyword; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.AscendAbility; import mage.constants.Outcome; -import mage.designations.CitysBlessing; -import mage.designations.DesignationType; -import mage.filter.StaticFilters; import mage.game.Game; -import mage.players.Player; /** * @@ -44,7 +41,7 @@ public class AscendEffect extends OneShotEffect { public AscendEffect() { super(Outcome.Detriment); - staticText = "Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)
"; + staticText = AscendAbility.ASCEND_RULE + "
"; } public AscendEffect(final AscendEffect effect) { @@ -58,20 +55,6 @@ public class AscendEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) { - if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) { - controller.addDesignation(new CitysBlessing()); - game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game."); - } else { - game.informPlayers(controller.getLogName() + " already has the city's blessing."); - } - } else { - game.informPlayers(controller.getLogName() + " does not get the city's blessing."); - } - return true; - } - return false; + return AscendAbility.checkAscend(game, source, true); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/AscendAbility.java b/Mage/src/main/java/mage/abilities/keyword/AscendAbility.java new file mode 100644 index 00000000000..0f35ff9d016 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/AscendAbility.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.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import static mage.abilities.keyword.AscendAbility.ASCEND_RULE; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.designations.CitysBlessing; +import mage.designations.DesignationType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LevelX2 + */ +public class AscendAbility extends SimpleStaticAbility { + + public static String ASCEND_RULE = "Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)"; + + public AscendAbility() { + super(Zone.BATTLEFIELD, new AscendContinuousEffect()); + } + + public AscendAbility(final AscendAbility ability) { + super(ability); + } + + @Override + public AscendAbility copy() { + return new AscendAbility(this); + } + + public static boolean checkAscend(Game game, Ability source, boolean verbose) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + if (!controller.hasDesignation(DesignationType.CITYS_BLESSING)) { + if (game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND, controller.getId(), game) > 9) { + controller.addDesignation(new CitysBlessing()); + game.informPlayers(controller.getLogName() + " gets the city's blessing for the rest of the game."); + } else { + if (verbose) { + game.informPlayers(controller.getLogName() + " does not get the city's blessing."); + } + } + } else { + if (verbose) { + game.informPlayers(controller.getLogName() + " already has the city's blessing."); + } + } + return true; + } + return false; + } + + @Override + public String getRule() { + return ASCEND_RULE; + } + +} + +class AscendContinuousEffect extends ContinuousEffectImpl { + + public AscendContinuousEffect() { + super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); + staticText = ASCEND_RULE; + } + + public AscendContinuousEffect(final AscendContinuousEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return AscendAbility.checkAscend(game, source, false); + } + + @Override + public AscendContinuousEffect copy() { + return new AscendContinuousEffect(this); + } +} diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 0e7f18bc02e..66006123414 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -61,6 +61,7 @@ public final class StaticFilters { public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE = new FilterCreaturePermanent(); public static final FilterCreaturePermanent FILTER_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES = new FilterCreaturePermanent("creatures"); + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES_CONTROLLED = new FilterCreaturePermanent("creatures you control"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_GOBLINS = new FilterCreaturePermanent(SubType.GOBLIN, "Goblin creatures"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures"); public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKER = new FilterPlaneswalkerPermanent(); @@ -108,6 +109,8 @@ public final class StaticFilters { FILTER_ATTACKING_CREATURES.add(new AttackingPredicate()); + FILTER_PERMANENT_CREATURES_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); + FILTER_PERMANENT_ARTIFACT_OR_CREATURE.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE) diff --git a/Mage/src/main/java/mage/watchers/WatcherUtils.java b/Mage/src/main/java/mage/watchers/WatcherUtils.java new file mode 100644 index 00000000000..ec717a98221 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/WatcherUtils.java @@ -0,0 +1,46 @@ +/* + * 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.watchers; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.game.Game; +import org.apache.log4j.Logger; + +/** + * + * @author LevelX2 + */ +public final class WatcherUtils { + + public static void logMissingWatcher(Game game, Ability source, Class watcherClass, Class usingClass) { + MageObject sourceObject = source.getSourceObject(game); + Logger.getLogger(usingClass).error("Needed watcher is not started " + watcherClass.getSimpleName() + + " - " + (sourceObject == null ? " no source object" : sourceObject.getName())); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java index 462f2db4083..9dce3c3c5ba 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java @@ -38,7 +38,7 @@ import mage.watchers.Watcher; /* * Counts amount of life lost current or last turn by players. - * This watcher is always added in gameImpl.init + * This watcher is automatically started in gameImpl.init for each game * * @author LevelX2 */ diff --git a/Utils/keywords.txt b/Utils/keywords.txt index 875ab52c008..f78722fbbbf 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -1,5 +1,6 @@ Afflict|number| Annihilator|number| +Ascend|new| Basic landcycling|cost| Battle cry|new| Bestow|card, manaString| From d5fa7af27037c386221f33354d525f9c63aa5874 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 18:07:58 +0100 Subject: [PATCH 40/54] [RIX] Minor text change for "The Immortal Sun". --- Mage.Sets/src/mage/cards/t/TheImmortalSun.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java index 96d723723e8..f8505beebff 100644 --- a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java +++ b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java @@ -62,7 +62,7 @@ public class TheImmortalSun extends CardImpl { this.addSuperType(SuperType.LEGENDARY); - // Players can't activate loyalty abilities of planeswalkers. + // Players can't activate planeswalkers' loyalty abilities. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TheImmortalSunCantActivateEffect())); // At the beginning of your draw step, draw an additional card. this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false)); @@ -86,7 +86,7 @@ class TheImmortalSunCantActivateEffect extends ContinuousRuleModifyingEffectImpl public TheImmortalSunCantActivateEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Players can't activate loyalty abilities of planeswalkers"; + staticText = "Players can't activate planeswalkers' loyalty abilities"; } public TheImmortalSunCantActivateEffect(final TheImmortalSunCantActivateEffect effect) { From bc490ef91a0ae35483a2d4e42241deef4f6fd5cc Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 23:48:07 +0100 Subject: [PATCH 41/54] Added Spellweaver Volute. --- .../src/mage/cards/s/SpellweaverVolute.java | 150 +++++ Mage.Sets/src/mage/sets/FutureSight.java | 1 + .../EnchantingGraveyardCardsTest.java | 220 +++++++ .../effects/common/AttachEffect.java | 9 + .../common/ChooseCreatureTypeEffect.java | 3 - Mage/src/main/java/mage/cards/Card.java | 12 +- Mage/src/main/java/mage/cards/CardImpl.java | 45 ++ Mage/src/main/java/mage/game/GameImpl.java | 9 + .../main/java/mage/game/events/GameEvent.java | 3 +- .../java/mage/game/permanent/Permanent.java | 7 +- .../mage/game/permanent/PermanentImpl.java | 117 ++-- Mage/src/main/java/mage/game/stack/Spell.java | 15 + .../main/java/mage/players/PlayerImpl.java | 11 +- Utils/gen-existing-cards-by-set.pl | 586 +++++++++--------- 14 files changed, 835 insertions(+), 353 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/s/SpellweaverVolute.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java new file mode 100644 index 00000000000..ea17f9d45c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java @@ -0,0 +1,150 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +/** + * + * @author LevelX2 + */ +public class SpellweaverVolute extends CardImpl { + + public SpellweaverVolute(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant instant card in a graveyard + FilterCard filter = new FilterCard("instant card in a graveyard"); + filter.add(new CardTypePredicate(CardType.INSTANT)); + TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost. + // If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard. + FilterSpell filterSpell = new FilterSpell("a sorcery spell"); + filterSpell.add(new CardTypePredicate(CardType.SORCERY)); + this.addAbility(new SpellCastControllerTriggeredAbility(new SpellweaverVoluteEffect(), filterSpell, false)); + } + + public SpellweaverVolute(final SpellweaverVolute card) { + super(card); + } + + @Override + public SpellweaverVolute copy() { + return new SpellweaverVolute(this); + } +} + +class SpellweaverVoluteEffect extends OneShotEffect { + + public SpellweaverVoluteEffect() { + super(Outcome.Benefit); + this.staticText = "copy the enchanted instant card. You may cast the copy without paying its mana cost. \n" + + "If you do, exile the enchanted card and attach {this} to another instant card in a graveyard"; + } + + public SpellweaverVoluteEffect(final SpellweaverVoluteEffect effect) { + super(effect); + } + + @Override + public SpellweaverVoluteEffect copy() { + return new SpellweaverVoluteEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null && sourcePermanent.getAttachedTo() != null) { + Card enchantedCard = game.getCard(sourcePermanent.getAttachedTo()); + if (enchantedCard != null && game.getState().getZone(enchantedCard.getId()) == Zone.GRAVEYARD) { + Player ownerEnchanted = game.getPlayer(enchantedCard.getOwnerId()); + if (ownerEnchanted != null + && controller.chooseUse(outcome, "Create a copy of " + enchantedCard.getName() + '?', source, game)) { + Card copiedCard = game.copyCard(enchantedCard, source, source.getControllerId()); + if (copiedCard != null) { + ownerEnchanted.getGraveyard().add(copiedCard); + game.getState().setZone(copiedCard.getId(), Zone.GRAVEYARD); + if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { + if (copiedCard.getSpellAbility() != null) { + controller.cast(copiedCard.getSpellAbility(), game, true); + } + if (controller.moveCards(enchantedCard, Zone.EXILED, source, game)) { + FilterCard filter = new FilterCard("instant card in a graveyard"); + filter.add(new CardTypePredicate(CardType.INSTANT)); + TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(filter); + if (auraTarget.canChoose(source.getSourceId(), controller.getId(), game)) { + controller.choose(outcome, auraTarget, source.getSourceId(), game); + Card newAuraTarget = game.getCard(auraTarget.getFirstTarget()); + if (newAuraTarget != null) { + if (enchantedCard.getId().equals(newAuraTarget.getId())) { + } else if (newAuraTarget.addAttachment(sourcePermanent.getId(), game)) { + game.informPlayers(sourcePermanent.getLogName() + " was attached to " + newAuraTarget.getLogName()); + } + } + } + } + + } + } + } + } + + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/FutureSight.java b/Mage.Sets/src/mage/sets/FutureSight.java index 6edb2d5ce9b..9f578ac5ff6 100644 --- a/Mage.Sets/src/mage/sets/FutureSight.java +++ b/Mage.Sets/src/mage/sets/FutureSight.java @@ -200,6 +200,7 @@ public class FutureSight extends ExpansionSet { cards.add(new SetCardInfo("Snake Cult Initiation", 89, Rarity.UNCOMMON, mage.cards.s.SnakeCultInitiation.class)); cards.add(new SetCardInfo("Soultether Golem", 164, Rarity.UNCOMMON, mage.cards.s.SoultetherGolem.class)); cards.add(new SetCardInfo("Sparkspitter", 109, Rarity.UNCOMMON, mage.cards.s.Sparkspitter.class)); + cards.add(new SetCardInfo("Spellweaver Volute", 59, Rarity.RARE, mage.cards.s.SpellweaverVolute.class)); cards.add(new SetCardInfo("Spellwild Ouphe", 151, Rarity.UNCOMMON, mage.cards.s.SpellwildOuphe.class)); cards.add(new SetCardInfo("Spin into Myth", 60, Rarity.UNCOMMON, mage.cards.s.SpinIntoMyth.class)); cards.add(new SetCardInfo("Spirit en-Dal", 17, Rarity.UNCOMMON, mage.cards.s.SpiritEnDal.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java new file mode 100644 index 00000000000..13bf22dd561 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java @@ -0,0 +1,220 @@ +/* + * 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 org.mage.test.cards.enchantments; + +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class EnchantingGraveyardCardsTest extends CardTestPlayerBase { + + static final String LIGHTNING_BOLT = "Lightning Bolt"; + static final String SPELLWEAVER_VOLUTE = "Spellweaver Volute"; + + /** + * Test that a card in the graveyard can be enchanted + */ + @Test + public void testSpellwaeverVoluteNormal() { + // Enchant instant card in a graveyard + // Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost. + // If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard. + addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + // Lightning Bolt deals 3 damage to target creature or player. + addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertHandCount(playerA, 0); + assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 1); + assertGraveyardCount(playerB, LIGHTNING_BOLT, 1); + + Permanent spellweaver = getPermanent(SPELLWEAVER_VOLUTE); + Card attachedToCard = null; + if (spellweaver != null) { + attachedToCard = playerB.getGraveyard().get(spellweaver.getAttachedTo(), currentGame); + } + Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Lightning Bolt in graveyard", attachedToCard != null && attachedToCard.getName().equals(LIGHTNING_BOLT)); + } + + /** + * Test that a card in the graveyard can be enchanted and the enchanted card + * switches to a new one + */ + @Test + public void testSpellwaeverVoluteAndSorcery() { + + // Enchant instant card in a graveyard + // Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost. + // If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard. + addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U} + addCard(Zone.HAND, playerA, "Cloak of Feathers"); // Sorcery {U} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.GRAVEYARD, playerA, "Aerial Volley", 1); // Instant {G} + + // Lightning Bolt deals 3 damage to target creature or player. + addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloak of Feathers", "Silvercoat Lion"); + setChoice(playerA, "Yes"); // play the L. Bold + addTarget(playerA, playerB); // Add Target for the L. Bold + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + assertHandCount(playerA, 1); + assertGraveyardCount(playerA, "Cloak of Feathers", 1); + assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 1); + assertGraveyardCount(playerA, "Aerial Volley", 1); + assertExileCount(playerB, LIGHTNING_BOLT, 1); + assertAbility(playerA, "Silvercoat Lion", FlyingAbility.getInstance(), true); + Permanent spellweaver = getPermanent(SPELLWEAVER_VOLUTE); + Card attachedToCard = null; + if (spellweaver != null) { + attachedToCard = playerA.getGraveyard().get(spellweaver.getAttachedTo(), currentGame); + } + Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Aerial Volley in graveyard", attachedToCard != null && attachedToCard.getName().equals("Aerial Volley")); + + assertHandCount(playerA, 1); + + } + + /** + * Test that a card in the graveyard can be enchanted and the enchanted card + * switches to a new one + */ + @Test + public void testSpellwaeverVoluteAndSorceryWithoutNewTarget() { + + // Enchant instant card in a graveyard + // Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost. + // If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard. + addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U} + addCard(Zone.HAND, playerA, "Cloak of Feathers"); // Sorcery {U} + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + // Lightning Bolt deals 3 damage to target creature or player. + addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloak of Feathers", "Silvercoat Lion"); + setChoice(playerA, "Yes"); // play the L. Bold + addTarget(playerA, playerB); // Add Target for the L. Bold + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 17); + + assertHandCount(playerA, 1); + assertGraveyardCount(playerA, "Cloak of Feathers", 1); + assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 0); + assertGraveyardCount(playerA, SPELLWEAVER_VOLUTE, 1); + assertExileCount(playerB, LIGHTNING_BOLT, 1); + assertAbility(playerA, "Silvercoat Lion", FlyingAbility.getInstance(), true); + + assertGraveyardCount(playerA, SPELLWEAVER_VOLUTE, 1); + + for (Card card : currentGame.getExile().getAllCards(currentGame)) { + if (card.getName().equals(LIGHTNING_BOLT)) { + Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty()); + + } + } + assertHandCount(playerA, 1); + + } + + /** + * Test that a card in the graveyard can be enchanted and if the Enchantment + * returns to hand, the enchanting ends + */ + @Test + public void testSpellwaeverVoluteAndReturnToHand() { + + // Enchant instant card in a graveyard + // Whenever you cast a sorcery spell, copy the enchanted instant card. You may cast the copy without paying its mana cost. + // If you do, exile the enchanted card and attach Spellweaver Volute to another instant card in a graveyard. + addCard(Zone.HAND, playerA, SPELLWEAVER_VOLUTE, 1); // Enchantment Aura {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + // Lightning Bolt deals 3 damage to target creature or player. + addCard(Zone.GRAVEYARD, playerB, "Lightning Bolt", 1); // Instant {R} + + // Return target permanent to its owner's hand. + addCard(Zone.HAND, playerB, "Boomerang", 1); // Instant {U}{U} + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, SPELLWEAVER_VOLUTE, LIGHTNING_BOLT); + + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Boomerang", SPELLWEAVER_VOLUTE); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertHandCount(playerA, SPELLWEAVER_VOLUTE, 1); + assertGraveyardCount(playerB, "Boomerang", 1); + assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 0); + + for (Card card : playerB.getGraveyard().getCards(currentGame)) { + if (card.getName().equals(LIGHTNING_BOLT)) { + Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty()); + + } + } + assertHandCount(playerA, 1); + + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java index 2fe23522239..efe93399ea8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java @@ -29,10 +29,12 @@ package mage.abilities.effects.common; import mage.abilities.Ability; 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.target.TargetCard; /** * @@ -72,9 +74,16 @@ public class AttachEffect extends OneShotEffect { if (player != null) { return player.addAttachment(source.getSourceId(), game); } + if (source.getTargets().get(0) instanceof TargetCard) { // e.g. Spellweaver Volute + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card != null) { + return card.addAttachment(source.getSourceId(), game); + } + } } } } + return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java index f707e908249..7af38326fb4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java @@ -27,14 +27,11 @@ */ package mage.abilities.effects.common; -import java.util.LinkedHashSet; -import java.util.stream.Collectors; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.choices.Choice; import mage.choices.ChoiceCreatureType; -import mage.choices.ChoiceImpl; import mage.constants.Outcome; import mage.constants.SubType; import mage.game.Game; diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 728951f59e4..16a30646ee0 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -27,6 +27,8 @@ */ package mage.cards; +import java.util.List; +import java.util.UUID; import mage.MageObject; import mage.Mana; import mage.ObjectColor; @@ -42,19 +44,14 @@ import mage.game.Game; import mage.game.GameState; import mage.game.permanent.Permanent; -import java.util.List; -import java.util.UUID; - public interface Card extends MageObject { - final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*"; final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*"; final String regexRed = ".*\\x7b.{0,2}R.{0,2}\\x7d.*"; final String regexGreen = ".*\\x7b.{0,2}G.{0,2}\\x7d.*"; final String regexWhite = ".*\\x7b.{0,2}W.{0,2}\\x7d.*"; - UUID getOwnerId(); String getCardNumber(); @@ -248,4 +245,9 @@ public interface Card extends MageObject { return mana; } + List getAttachments(); + + boolean addAttachment(UUID permanentId, Game game); + + boolean removeAttachment(UUID permanentId, Game game); } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index d2f8d1a2300..4c9aaf5397b 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -94,6 +94,8 @@ public abstract class CardImpl extends MageObjectImpl implements Card { protected boolean morphCard; protected boolean allCreatureTypes; + protected List attachments = new ArrayList<>(); + public CardImpl(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs) { this(ownerId, setInfo, cardTypes, costs, SpellAbilityType.BASE); } @@ -169,6 +171,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { flipCardName = card.flipCardName; splitCard = card.splitCard; usesVariousArt = card.usesVariousArt; + this.attachments.addAll(card.attachments); } @Override @@ -840,11 +843,53 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return super.getSubtype(game); } + @Override public boolean isAllCreatureTypes() { return allCreatureTypes; } + @Override public void setIsAllCreatureTypes(boolean value) { allCreatureTypes = value; } + + @Override + public List getAttachments() { + return attachments; + } + + @Override + public boolean addAttachment(UUID permanentId, Game game) { + if (!this.attachments.contains(permanentId)) { + Permanent attachment = game.getPermanent(permanentId); + if (attachment == null) { + attachment = game.getPermanentEntering(permanentId); + } + if (attachment != null) { + if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, attachment.getControllerId()))) { + this.attachments.add(permanentId); + attachment.attachTo(objectId, game); + game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, attachment.getControllerId())); + return true; + } + } + } + return false; + } + + @Override + public boolean removeAttachment(UUID permanentId, Game game) { + if (this.attachments.contains(permanentId)) { + Permanent attachment = game.getPermanent(permanentId); + if (attachment != null) { + attachment.unattach(game); + } + if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, attachment != null ? attachment.getControllerId() : null))) { + this.attachments.remove(permanentId); + game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, attachment != null ? attachment.getControllerId() : null)); + return true; + } + } + return false; + } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 7b5e10477b5..52c0856a99a 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1901,6 +1901,15 @@ public abstract class GameImpl implements Game, Serializable { } } } + } else if (target instanceof TargetCard) { + Card attachedTo = getCard(perm.getAttachedTo()); + if (attachedTo == null + || !((TargetCard) spellAbility.getTargets().get(0)).canTarget(perm.getControllerId(), perm.getAttachedTo(), spellAbility, this)) { + if (movePermanentToGraveyardWithInfo(perm)) { + attachedTo.removeAttachment(perm.getId(), this); + somethingHappened = true; + } + } } } } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index 34c8357a0dc..c4997302d54 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -233,7 +233,8 @@ public class GameEvent implements Serializable { PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, //permanent events - ENTERS_THE_BATTLEFIELD_SELF, // 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b. + ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), + one of them must be chosen. If not, proceed to rule 616.1b. */ ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b ENTERS_THE_BATTLEFIELD_COPY, // 616.1c ENTERS_THE_BATTLEFIELD, // 616.1d diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 45e8226439f..b361f3abe55 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -116,10 +116,11 @@ public interface Permanent extends Card, Controllable { void attachTo(UUID permanentId, Game game); - boolean addAttachment(UUID permanentId, Game game); - - boolean removeAttachment(UUID permanentId, Game game); + void unattach(Game game); +// boolean addAttachment(UUID permanentId, Game game); +// +// boolean removeAttachment(UUID permanentId, Game game); boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game); boolean hasProtectionFrom(MageObject source, Game game); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 95c27b3c634..b3beae95df6 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -56,6 +56,7 @@ import mage.game.permanent.token.SquirrelToken; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; +import mage.target.TargetCard; import mage.util.CardUtil; import mage.util.GameLog; import mage.util.ThreadLocalStringBuilder; @@ -103,7 +104,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected int maxBlockedBy = 0; protected boolean removedFromCombat; protected boolean deathtouched; - protected List attachments = new ArrayList<>(); + protected Map> connectedCards = new HashMap<>(); protected Set dealtDamageByThisTurn; protected UUID attachedTo; @@ -147,7 +148,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.blocking = permanent.blocking; this.maxBlocks = permanent.maxBlocks; this.deathtouched = permanent.deathtouched; - this.attachments.addAll(permanent.attachments); +// this.attachments.addAll(permanent.attachments); for (Map.Entry> entry : permanent.connectedCards.entrySet()) { this.connectedCards.put(entry.getKey(), entry.getValue()); } @@ -626,47 +627,46 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } return false; } +// +// @Override +// public List getAttachments() { +// return attachments; +// } - @Override - public List getAttachments() { - return attachments; - } - - @Override - public boolean addAttachment(UUID permanentId, Game game) { - if (!this.attachments.contains(permanentId)) { - if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) { - this.attachments.add(permanentId); - Permanent attachment = game.getPermanent(permanentId); - if (attachment == null) { - attachment = game.getPermanentEntering(permanentId); - } - if (attachment != null) { - attachment.attachTo(objectId, game); - game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId)); - return true; - } - } - } - return false; - } - - @Override - public boolean removeAttachment(UUID permanentId, Game game) { - if (this.attachments.contains(permanentId)) { - if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) { - this.attachments.remove(permanentId); - Permanent attachment = game.getPermanent(permanentId); - if (attachment != null) { - attachment.attachTo(null, game); - } - game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId)); - return true; - } - } - return false; - } - +// @Override +// public boolean addAttachment(UUID permanentId, Game game) { +// if (!this.attachments.contains(permanentId)) { +// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.ATTACH, objectId, permanentId, controllerId))) { +// this.attachments.add(permanentId); +// Permanent attachment = game.getPermanent(permanentId); +// if (attachment == null) { +// attachment = game.getPermanentEntering(permanentId); +// } +// if (attachment != null) { +// attachment.attachTo(objectId, game); +// game.fireEvent(new GameEvent(GameEvent.EventType.ATTACHED, objectId, permanentId, controllerId)); +// return true; +// } +// } +// } +// return false; +// } +// +// @Override +// public boolean removeAttachment(UUID permanentId, Game game) { +// if (this.attachments.contains(permanentId)) { +// if (!game.replaceEvent(new GameEvent(GameEvent.EventType.UNATTACH, objectId, permanentId, controllerId))) { +// this.attachments.remove(permanentId); +// Permanent attachment = game.getPermanent(permanentId); +// if (attachment != null) { +// attachment.attachTo(null, game); +// } +// game.fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, objectId, permanentId, controllerId)); +// return true; +// } +// } +// return false; +// } @Override public UUID getAttachedTo() { return attachedTo; @@ -705,15 +705,27 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } @Override - public void attachTo(UUID permanentId, Game game) { - if (this.attachedTo != null && !Objects.equals(this.attachedTo, permanentId)) { - Permanent attachment = game.getPermanent(this.attachedTo); - if (attachment != null) { - attachment.removeAttachment(this.objectId, game); + public void unattach(Game game) { + this.attachedTo = null; + this.addInfo("attachedToCard", null, game); + } + + @Override + public void attachTo(UUID attachToObjectId, Game game) { + if (this.attachedTo != null && !Objects.equals(this.attachedTo, attachToObjectId)) { + Permanent attachedToUntilNowObject = game.getPermanent(this.attachedTo); + if (attachedToUntilNowObject != null) { + attachedToUntilNowObject.removeAttachment(this.objectId, game); + } else { + Card attachedToUntilNowCard = game.getCard(this.attachedTo); + if (attachedToUntilNowCard != null) { + attachedToUntilNowCard.removeAttachment(this.objectId, game); + } } + } - this.attachedTo = permanentId; - this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(permanentId); + this.attachedTo = attachToObjectId; + this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId); for (Ability ability : this.getAbilities()) { for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) { ContinuousEffect effect = (ContinuousEffect) ite.next(); @@ -726,6 +738,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } } + if (!getSpellAbility().getTargets().isEmpty() && (getSpellAbility().getTargets().get(0) instanceof TargetCard)) { + Card attachedToCard = game.getCard(this.getAttachedTo()); + if (attachedToCard != null) { + // Because cards are not on the battlefield, the relation has to be shown in the card tooltip (e.g. the enchanted card in graveyard) + this.addInfo("attachedToCard", CardUtil.addToolTipMarkTags("Enchanted card: " + attachedToCard.getIdName()), game); + } + } } @Override diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 0b76841eab2..c342549d36a 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -955,4 +955,19 @@ public class Spell extends StackObjImpl implements Card { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + @Override + public List getAttachments() { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean addAttachment(UUID permanentId, Game game) { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean removeAttachment(UUID permanentId, Game game) { + throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates. + } + } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1301f196972..bf43c6ad758 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -817,6 +817,11 @@ public abstract class PlayerImpl implements Player, Serializable { Player attachedToPlayer = game.getPlayer(permanent.getAttachedTo()); if (attachedToPlayer != null) { attachedToPlayer.removeAttachment(permanent, game); + } else { + Card attachedToCard = game.getCard(permanent.getAttachedTo()); + if (attachedToCard != null) { + attachedToCard.removeAttachment(permanent.getId(), game); + } } } @@ -2326,7 +2331,7 @@ public abstract class PlayerImpl implements Player, Serializable { newTarget.setCardLimit(Math.min(librarySearchLimit, cardsFromTop.size())); count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit); } - + if (count < target.getNumberOfTargets()) { newTarget.setMinNumberOfTargets(count); } @@ -3278,9 +3283,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCards(Card card, Zone toZone, - Ability source, Game game - ) { + public boolean moveCards(Card card, Zone toZone, Ability source, Game game) { return moveCards(card, toZone, source, game, false, false, false, null); } diff --git a/Utils/gen-existing-cards-by-set.pl b/Utils/gen-existing-cards-by-set.pl index 9c6e0a4f7ff..93462c3ad92 100755 --- a/Utils/gen-existing-cards-by-set.pl +++ b/Utils/gen-existing-cards-by-set.pl @@ -1,288 +1,298 @@ -#!/usr/bin/perl -w - -#author: North - -use Text::Template; -use strict; - - -my $authorFile = 'author.txt'; -my $dataFile = "mtg-cards-data.txt"; -my $setsFile = "mtg-sets-data.txt"; -my $knownSetsFile = "known-sets.txt"; - - -my %cards; -my %sets; -my %knownSets; - -my @setCards; - -# gets the set name -my $setName = $ARGV[0]; -if(!$setName) { - print 'Enter a set name: '; - $setName = ; - chomp $setName; -} - -my $template = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedClass.tmpl', DELIMITERS => [ '[=', '=]' ]); -my $templateBasicLand = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedLandClass.tmpl', DELIMITERS => [ '[=', '=]' ]); - -sub toCamelCase { - my $string = $_[0]; - $string =~ s/\b([\w']+)\b/ucfirst($1)/ge; - $string =~ s/[-,\s\'\/]//g; - $string; -} - -my $author; -if (-e $authorFile) { - open (DATA, $authorFile); - $author = ; - close(DATA); -} else { - $author = 'anonymous'; -} - -my $cardsFound = 0; -my %all_sets; - -print ("Opening $dataFile\n"); -open (DATA, $dataFile) || die "can't open $dataFile"; -while(my $line = ) { - my @data = split('\\|', $line); - $cards{$data[0]}{$data[1]} = \@data; - - if ($data[1] eq $setName) { - my $cardInfo = "$data[0],,,$data[2]"; - - push(@setCards, $cardInfo); - } else { - $all_sets {$data[1]} = 1; - } -} - -# Fix up split cards -my $potentialSideA; -my @tempSetCards; - -foreach $potentialSideA (sort @setCards) { - #print (">>$potentialSideA\n"); - if ($potentialSideA =~ m/.*,,,(\d+)(a)$/) { - my $cardNumSideB = $1 . "b"; - my $orig_cardNumSideB = $1 . "b"; - my $val; - foreach $val (sort @setCards) { - if ($val =~ m/$cardNumSideB$/) { - $potentialSideA =~ s/,,,.*//; - $val =~ s/,,,.*//; - - # Add 'SideaSideb' to %cards - my $ds = $cards{$val}{$setName}; - print ("$potentialSideA$val,,,$cardNumSideB\n"); - my @newCard; - push (@newCard, "$potentialSideA$val"); - push (@newCard, "$setName"); - push (@newCard, "SPLIT"); - push (@newCard, @$ds[3]); - push (@newCard, "$potentialSideA // $val"); - $cards{$newCard[0]}{$newCard[1]} = \@newCard; - - $cardNumSideB =~ s/.$//; - push (@tempSetCards, "$potentialSideA$val,,,$cardNumSideB"); - - print ("Adding in: $potentialSideA \/\/ $val,,,$cardNumSideB\n"); - $cardsFound = $cardsFound - 1; - $cardNumSideB = $orig_cardNumSideB; - } - } - } - elsif ($potentialSideA =~ m/.*,,,(\d+)(b)$/) { - next; - } - else { - $cardsFound = $cardsFound + 1; - push (@tempSetCards, $potentialSideA); - } -} -@setCards = @tempSetCards; - -close(DATA); -print "Number of cards found for set " . $setName . ": " . $cardsFound . "\n"; - - -if ($cardsFound == 0) { - $setName =~ s/^(...).*/$1/; - my $poss; - my $foundPossibleSet = 0; - my $numPossibleSets = 0; - foreach $poss (sort keys (%all_sets)) { - $numPossibleSets++; - if ($poss =~ m/^$setName/i) { - print ("Did you possibly mean: $poss ?\n"); - $foundPossibleSet = 1; - } - } - if (!$foundPossibleSet) { - print ("Couldn't find any matching set for '$setName'. \n"); - } - - print "(Note: Looked at $numPossibleSets sets in total).\nPress the enter key to exit."; - $setName = ; - exit; -} - -open (DATA, $setsFile) || die "can't open $setsFile"; - -while(my $line = ) { - my @data = split('\\|', $line); - $sets{$data[0]}= $data[1]; -} -close(DATA); - -open (DATA, $knownSetsFile) || die "can't open $knownSetsFile"; -while(my $line = ) { - my @data = split('\\|', $line); - $knownSets{$data[0]}= $data[1]; -} -close(DATA); - -my %raritiesConversion; -$raritiesConversion{'C'} = 'COMMON'; -$raritiesConversion{'U'} = 'UNCOMMON'; -$raritiesConversion{'R'} = 'RARE'; -$raritiesConversion{'M'} = 'MYTHIC'; -$raritiesConversion{'Special'} = 'SPECIAL'; -$raritiesConversion{'Bonus'} = 'BONUS'; -sub getRarity -{ - my $val = $_ [0]; - if (exists ($raritiesConversion {$val})) - { - return $raritiesConversion {$val}; - } - print ("ERROR DETECTED! - Incorrect rarity.. --- $val,,,$_[1]\n"); - sleep (10); - print "Press the enter key to exit."; - $setName = ; - exit; -} - -# Generate the cards - -my %vars; -$vars{'author'} = $author; -$vars{'set'} = $knownSets{$setName}; -$vars{'expansionSetCode'} = $sets{$setName}; - -my $landForest = 0; -my $landMountain = 0; -my $landSwamp = 0; -my $landPlains = 0; -my $landIsland = 0; - -print ("Reading in existing cards in set\n"); -open (SET_FILE, "../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java") || die "can't open $dataFile"; -my %alreadyIn; -while () { - my $line = $_; - if ($line =~ m/SetCardInfo.*\("(.*)", (\d+).*/) - { - $alreadyIn {$2} = $1; - } -} -close SET_FILE; - -my $name_collectorid; -my %implemented; -my %implementedButNotInSetYet; -my %unimplemented; - - -my %githubTask; - -foreach $name_collectorid (sort @setCards) -{ - my $cardName; - my $cardNr; - $name_collectorid =~ m/^(.*),,,(.*)$/; - $cardName = $1; - $cardNr = $2; - { - if($cardName eq "Forest" || $cardName eq "Island" || $cardName eq "Plains" || $cardName eq "Swamp" || $cardName eq "Mountain") { - my $found = 0; - if ($cardName eq "Forest") { - $landForest++; - } - if ($cardName eq "Mountain") { - $landMountain++; - } - if ($cardName eq "Swamp") { - $landSwamp++; - } - if ($cardName eq "Plains") { - $landPlains++; - } - if ($cardName eq "Island") { - $landIsland++; - } - if (!exists ($alreadyIn{$cardNr})) { - print (" cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity.LAND, mage.cards.basiclands.$cardName.class, USE_RANDOM_ART));\n"); - } - } - else { - my $ds; - $ds = $cards{$cardName}{$setName}; - my $className = toCamelCase($cardName); - my $setId = lc($cardName); - $setId =~ s/^(.).*/$1/; - my $googleSetName = $setName; - $googleSetName =~ s/ /+/img; - my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java"; - my $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$cardName}{$setName}[3], $cardName) . ", mage.cards.$setId.$className.class));\n"; - - if (@$ds[2] eq "SPLIT") { - my $oldCardName = $cardName; - $cardName = @$ds[4]; - $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$oldCardName}{$setName}[3], $oldCardName) . ", mage.cards.$setId.$className.class));\n"; - } - - my $plus_cardName = $cardName; - $plus_cardName =~ s/ /+/img; - $plus_cardName =~ s/,/+/img; - $plus_cardName = "intext:\"$plus_cardName\""; - - if (!exists ($alreadyIn{$cardNr})) { -# Go Looking for the existing implementation.. - if (-e $fn) { - $implementedButNotInSetYet {$str} = 1; - $githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; - } else { - $unimplemented {"$str"} = 1; - $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; - } - } else { - if (-e $fn) { - $implemented {$str} = 1; - $githubTask {"- [x] Done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; - } else { - $unimplemented {$str} = 1; - $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; - } - } - } - } -} - -print "Implemented cards:\n"; -print (join ("", sort keys (%implemented))); -print "\n\n\nImplemented but-not-yet-added-to-set cards:\n"; -print (join ("", sort keys (%implementedButNotInSetYet))); -print "\n\n\nUnimplemented cards:\n"; -print (join ("", sort keys (%unimplemented))); -print "\n\n\nGithub Task:\n"; -print (join ("", sort keys (%githubTask))); -print ("\nData from reading: ../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java\n"); -print "\n\nYou are done. Press the enter key to exit."; -$setName = ; +#!/usr/bin/perl -w + +#author: North + +use Text::Template; +use strict; + + +my $authorFile = 'author.txt'; +my $dataFile = "mtg-cards-data.txt"; +my $setsFile = "mtg-sets-data.txt"; +my $knownSetsFile = "known-sets.txt"; + + +my %cards; +my %sets; +my %knownSets; + +my @setCards; + +# gets the set name +my $setName = $ARGV[0]; +if(!$setName) { + print 'Enter a set name: '; + $setName = ; + chomp $setName; +} + +my $template = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedClass.tmpl', DELIMITERS => [ '[=', '=]' ]); +my $templateBasicLand = Text::Template->new(TYPE => 'FILE', SOURCE => 'cardExtendedLandClass.tmpl', DELIMITERS => [ '[=', '=]' ]); + +sub toCamelCase { + my $string = $_[0]; + $string =~ s/\b([\w']+)\b/ucfirst($1)/ge; + $string =~ s/[-,\s\'\/]//g; + $string; +} + +my $author; +if (-e $authorFile) { + open (DATA, $authorFile); + $author = ; + close(DATA); +} else { + $author = 'anonymous'; +} + +my $cardsFound = 0; +my %all_sets; + +print ("Opening $dataFile\n"); +open (DATA, $dataFile) || die "can't open $dataFile"; +while(my $line = ) { + my @data = split('\\|', $line); + $cards{$data[0]}{$data[1]} = \@data; + + if ($data[1] eq $setName) { + my $cardInfo = "$data[0],,,$data[2]"; + + push(@setCards, $cardInfo); + } else { + $all_sets {$data[1]} = 1; + } +} + +# Fix up split cards +my $potentialSideA; +my @tempSetCards; + +foreach $potentialSideA (sort @setCards) { + #print (">>$potentialSideA\n"); + if ($potentialSideA =~ m/.*,,,(\d+)(a)$/) { + my $cardNumSideB = $1 . "b"; + my $orig_cardNumSideB = $1 . "b"; + my $val; + foreach $val (sort @setCards) { + if ($val =~ m/$cardNumSideB$/) { + $potentialSideA =~ s/,,,.*//; + $val =~ s/,,,.*//; + + # Add 'SideaSideb' to %cards + my $ds = $cards{$val}{$setName}; + print ("$potentialSideA$val,,,$cardNumSideB\n"); + my @newCard; + push (@newCard, "$potentialSideA$val"); + push (@newCard, "$setName"); + push (@newCard, "SPLIT"); + push (@newCard, @$ds[3]); + push (@newCard, "$potentialSideA // $val"); + $cards{$newCard[0]}{$newCard[1]} = \@newCard; + + $cardNumSideB =~ s/.$//; + push (@tempSetCards, "$potentialSideA$val,,,$cardNumSideB"); + + print ("Adding in: $potentialSideA \/\/ $val,,,$cardNumSideB\n"); + $cardsFound = $cardsFound - 1; + $cardNumSideB = $orig_cardNumSideB; + } + } + } + elsif ($potentialSideA =~ m/.*,,,(\d+)(b)$/) { + next; + } + else { + $cardsFound = $cardsFound + 1; + push (@tempSetCards, $potentialSideA); + } +} +@setCards = @tempSetCards; + +close(DATA); +print "Number of cards found for set " . $setName . ": " . $cardsFound . "\n"; + + +if ($cardsFound == 0) { + $setName =~ s/^(...).*/$1/; + my $poss; + my $foundPossibleSet = 0; + my $numPossibleSets = 0; + foreach $poss (sort keys (%all_sets)) { + $numPossibleSets++; + if ($poss =~ m/^$setName/i) { + print ("Did you possibly mean: $poss ?\n"); + $foundPossibleSet = 1; + } + } + if (!$foundPossibleSet) { + print ("Couldn't find any matching set for '$setName'. \n"); + } + + print "(Note: Looked at $numPossibleSets sets in total).\nPress the enter key to exit."; + $setName = ; + exit; +} + +open (DATA, $setsFile) || die "can't open $setsFile"; + +while(my $line = ) { + my @data = split('\\|', $line); + $sets{$data[0]}= $data[1]; +} +close(DATA); + +open (DATA, $knownSetsFile) || die "can't open $knownSetsFile"; +while(my $line = ) { + my @data = split('\\|', $line); + $knownSets{$data[0]}= $data[1]; +} +close(DATA); + +my %raritiesConversion; +$raritiesConversion{'C'} = 'COMMON'; +$raritiesConversion{'U'} = 'UNCOMMON'; +$raritiesConversion{'R'} = 'RARE'; +$raritiesConversion{'M'} = 'MYTHIC'; +$raritiesConversion{'Special'} = 'SPECIAL'; +$raritiesConversion{'Bonus'} = 'BONUS'; +sub getRarity +{ + my $val = $_ [0]; + if (exists ($raritiesConversion {$val})) + { + return $raritiesConversion {$val}; + } + print ("ERROR DETECTED! - Incorrect rarity.. --- $val,,,$_[1]\n"); + sleep (10); + print "Press the enter key to exit."; + $setName = ; + exit; +} + +# Generate the cards + +my %vars; +$vars{'author'} = $author; +$vars{'set'} = $knownSets{$setName}; +$vars{'expansionSetCode'} = $sets{$setName}; + +my $landForest = 0; +my $landMountain = 0; +my $landSwamp = 0; +my $landPlains = 0; +my $landIsland = 0; + +print ("Reading in existing cards in set\n"); +open (SET_FILE, "../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java") || die "can't open $dataFile"; +my %alreadyIn; +while () { + my $line = $_; + if ($line =~ m/SetCardInfo.*\("(.*)", (\d+).*/) + { + $alreadyIn {$2} = $1; + } +} +close SET_FILE; + +my $name_collectorid; +my %implemented; +my %implementedButNotInSetYet; +my %unimplemented; + + +my %githubTask; + +foreach $name_collectorid (sort @setCards) +{ + my $cardName; + my $cardNr; + $name_collectorid =~ m/^(.*),,,(.*)$/; + $cardName = $1; + $cardNr = $2; + { + if($cardName eq "Forest" || $cardName eq "Island" || $cardName eq "Plains" || $cardName eq "Swamp" || $cardName eq "Mountain") { + my $found = 0; + if ($cardName eq "Forest") { + $landForest++; + } + if ($cardName eq "Mountain") { + $landMountain++; + } + if ($cardName eq "Swamp") { + $landSwamp++; + } + if ($cardName eq "Plains") { + $landPlains++; + } + if ($cardName eq "Island") { + $landIsland++; + } + if (!exists ($alreadyIn{$cardNr})) { + print (" cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity.LAND, mage.cards.basiclands.$cardName.class, USE_RANDOM_ART));\n"); + } + } + else { + my $ds; + $ds = $cards{$cardName}{$setName}; + my $className = toCamelCase($cardName); + my $setId = lc($cardName); + $setId =~ s/^(.).*/$1/; + my $googleSetName = $setName; + $googleSetName =~ s/ /+/img; + my $fn = "..\\Mage.Sets\\src\\mage\\cards\\$setId\\$className.java"; + my $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$cardName}{$setName}[3], $cardName) . ", mage.cards.$setId.$className.class));\n"; + + if (@$ds[2] eq "SPLIT") { + my $oldCardName = $cardName; + $cardName = @$ds[4]; + $str = " cards.add(new SetCardInfo(\"$cardName\", $cardNr, Rarity." . getRarity ($cards{$oldCardName}{$setName}[3], $oldCardName) . ", mage.cards.$setId.$className.class));\n"; + } + + my $plus_cardName = $cardName; + $plus_cardName =~ s/ /+/img; + $plus_cardName =~ s/,/+/img; + $plus_cardName = "intext:\"$plus_cardName\""; + + if (!exists ($alreadyIn{$cardNr})) { +# Go Looking for the existing implementation.. + if (-e $fn) { + $implementedButNotInSetYet {$str} = 1; + $githubTask {"- [ ] Implemented but have to add to set -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + } else { + $unimplemented {"$str"} = 1; + $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + } + } else { + if (-e $fn) { + $implemented {$str} = 1; + $githubTask {"- [x] Done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + } else { + $unimplemented {$str} = 1; + $githubTask {"- [ ] Not done -- [$cardName](https://www.google.com.au/search?q=$plus_cardName+$googleSetName+mtg&source=lnms&tbm=isch)\n"} = 1; + } + } + } + } +} + +# Add logic to add the missing card lines to set file automatically +#my $setFileName = "../Mage.Sets/src/mage/sets/".$knownSets{$setName}.".java"; +#print (join("","Add already implemented cards to set file: ", $setFileName,"\n")); +#foreach my $line (sort keys (%implementedButNotInSetYet)) { +# - Do action to add the line +# print $line; +#} + + +print "Implemented cards:\n"; +print (join ("", sort keys (%implemented))); +print "\n\n\nImplemented but-not-yet-added-to-set cards:\n"; +print (join ("", sort keys (%implementedButNotInSetYet))); +print "\n\n\nUnimplemented cards:\n"; +print (join ("", sort keys (%unimplemented))); +print "\n\n\nGithub Task:\n"; +print (join ("", sort keys (%githubTask))); +print ("\nData from reading: ../../mage/Mage.Sets/src/mage/sets/$knownSets{$setName}.java\n"); + +print "\n\nYou are done. Press the enter key to exit."; +$setName = ; From b0b5fe203601bd6b332e31ac8d5b9f53fcae426d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 2 Jan 2018 23:57:46 +0100 Subject: [PATCH 42/54] [RIX] Updated mtg-cards-data.txt with spoilers of 2018-01-03 00:00 CET --- Utils/mtg-cards-data.txt | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 091ab4951c1..fa74794d1dd 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -32696,36 +32696,52 @@ Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G} to yo Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to target creature or player, where X is the number of Gremlins you control.| Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)| Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.| +Famished Paladin|Rivals of Ixalan|8|U|{1}{W}|Creature - Vampire Knight|3|3|Famished Paladin does not untap during your untap step.$Whenever you gain life, untap Famished Paladin.| Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to it's toughness.| Glorious Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$As Glorious Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.| -Shrine Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source would deal damage to another Dinosaur you control, prevent all but 1 of that damage.| +Skynarcher Aspirant|Rivals of Ixalan|21|U|{W}|Creature - Vampire Soldier|2|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Skymarcher Aspirant has flying as long as you have the city's blessing| +Temple Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source would deal damage to another Dinosaur you control, prevent all but 1 of that damage.| Zetalpa, Primal Dawn|Rivals of Ixalan|30|R|{6}{W}{W}|Legendary Creature - Elder Dinosaur|4|8|Flying, double strike, vigilance, trample, indestructible| +Admiral's Order|Rivals of Ixalan|31|R|{1}{U}{U}|Instant|||Raid — If you attacked with a creature this turn, you may pay {U} rather than pay this spell's mana cost.$Counter target spell.| +Aquatic Incursion|Rivals of Ixalan|32|U|{3}{U}|Enchantment|||When Aquatic Incursion enters the battlefield, create two 1/1 blue Merfolk creature tokens with hexproof.${3}{U}: Target Merfolk can't be blocked this turn.| +Induced Amnesia|Rivals of Ixalan|40|R|{2}{U}|Enchantment|||When Induced Amnesia enters the battlefield, target player exiles all the cards in his or her hand face down, then draws that many cards.$When Induced Amnesia is put into a graveyard from the battlefield, return the exiled cards to their owner's hand.| +Kumena's Awakening|Rivals of Ixalan|42|R|{2}{U}{U}|Enchantment|||Ascend (If you control ten or more permenants, you get the city's blessing for the rest of the game.)$At the beginning of your upkeep, each player draws a card. If you have the city's blessing, instead only you draw a card.| River Darter|Rivals of Ixalan|47|C|{2}{U}|Creature - Merfolk Warrior|2|3|River Darter can't be blocked by Dinosaurs.| Seafloor Oracle|Rivals of Ixalan|51|R|{2}{W}{W}|Creature - Merfolk Wizard|2|3|Whenever a Merfolk you controls deals combat damage to a player, draw a card.| Secrets of the Golden City|Rivals of Ixalan|52|C|{1}{U}{U}|Sorcery|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Draw two cards. If you have the city's blessing, draw three cards instead.| Silvergill Adept|Rivals of Ixalan|53|U|{1}{U}|Creature - Merfolk Wizard|2|1|As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.$When Silvergill Adept enters the battlefield, draw a card.| +Timestream Navigator|Rivals of Ixalan|59|M|{1}{U}|Creature - Human Pirate Wizard|1|1|Ascend (If you control ten or more permanents, you gain The City's Blessing for the rest of the game.)${2}{U}{U}, {T}, Put Timestream Navigator at the bottom of its owner's library: Take an extra turn after this one. Activate this ability only if you have The City's Blessing.| Dusk Charger|Rivals of Ixalan|69|C|{3}{B}|Creature - Horse|3|3|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Dusk Charger gets +2/+2 as long as you have the city's blessing.| +Ravenous Chupacabra|Rivals of Ixalan|82|U|{2}{B}{B}|Creature - Beast Horror|2|2|When Ravenous Chupacabra enters the battlefield, destroy target creature an opponent controls.| Tetzimoc, Primal Death|Rivals of Ixalan|86|R|{4}{B}{B}|Legendary Creature - Elder Dinosaur|6|6|Deathtouch${B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.$When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it.| Vona's Hunger|Rivals of Ixalan|90|R|{2}{B}|Instant|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Each opponent sacrifices a creature. If you have the city's blessing, instead each opponent sacrifices half the creatures he or she controls rounded up.| Brass's Bounty|Rivals of Ixalan|94|R|{6}{R}|Sorcery|||For each land you control, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| +Daring Buccaneer|Rivals of Ixalan|98|U|{R}|Creature - Human Pirate|2|2|As an additional cost to cast Daring Buccaneer, reveal a Pirate card from your hand or pay 2.| +Etali, Primal Storm|Rivals of Ixalan|100|R|{4}{R}{R}|Legendary Creature - Elder Dinosaur|6|6|Whenever Etali, Primal Storm attacks, exile the top card of each player's library, then you may cast any number of nonland cards exiled this way without paying their mana costs.| Form of the Dinosaur|Rivals of Ixalan|103|R|{4}{R}{R}|Enchantment|||When Form of the Dinosaur enters the battlefield, your life total becomes 15.$At the beginning of your upkeep, Form of the Dinosaur deals 15 damage to target creature an opponent controls and that creature deals damage equal to its power to you.| Frilled Deathspitter|Rivals of Ixalan|104|C|{2}{R}|Creature - Dinosaur|3|2|Enrage — Whenever Frilled Deathspitter is dealt damage, it deals 2 damage to target opponent.| Swaggering Corsair|Rivals of Ixalan|119|C|{2}{R}|Creature - Human Pirate|2|2|Raid — Swaggering Corsair enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn.| Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step, unless you have the City's blessing.| Enter the Unknown|Rivals of Ixalan|128|U|{G}|Sorcery|||Target creature you control explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.) $You may play an additional land this turn.| Ghalta, Primal Hunger|Rivals of Ixalan|130|R|{1}{0}{G}{G}|Legendary Creature - Elder Dinosaur|12|12|Ghalta, Primal Hunger costs {X} less to cast, where X is the total power of creatures you control.$Trample| +Jadelight Ranger|Rivals of Ixalan|136|R|{1}{G}{G}|Creature - Merfolk Scout|2|1|When Jadelight Ranger enters the battlefield it explores, then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process) | Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)| +Swift Warden|Rivals of Ixalan|146|U|{1}{G}{G}|Creature - Merfolk Warrior|3|3|When Swift Warden enters the battlefield, target Merfolk you control gains hexproof until end of turn. (It can't be the target of spells or abilities your opponents control)| Tendershoot Dryad|Rivals of Ixalan|147|R|{4}{G}|Creature - Dryad|2|2|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$At the beginning of each upkeep, create a 1/1 green Saproling creature token.$Saprolings you control get +2/+2 as long as you have the city's blessing.| Thrashing Brontodon|Rivals of Ixalan|148|U|{1}{G}{G}|Creature - Dinosaur|3|4|{1}, Sacrificing Thrashing Brontodon: Destroy target artifact or enchantment.| +World Shaper|Rivals of Ixalan|151|R|{3}{G}|Creature - Merfolk Shaman|3|3|Whenever World Shaper attacks, you may put the top three cards of your library into your graveyard.$When World Shaper dies, put all land cards from your graveyard onto the battlefield tapped.| Angrath, the Flame-Chained|Rivals of Ixalan|152|M|{3}{B}{R}|Legendary Planeswalker - Angrath|4|+1: Each opponent discards a card and loses 2 life.$-3: Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. Sacrifice it at the beginning of the next end step if it has converted mana cost 3 or less.$-8: Each opponent loses life equal to the number of cards in his or her graveyard.| Atzocan Seer|Rivals of Ixalan|153|U|{1}{G}{W}|Creature - Human Druid|2|3|{t}: Add one mana of any color to your manan pool.$Sacrifice Atzocan Seer: Return target Dinosaur card from your graveyard to your hand.| Elenda, the Dusk Rose|Rivals of Ixalan|157|M|{2}{W}{B}|Legendary Creature - Vampire Knight|1|1|Lifelink$Whenever another creature dies, put a +1/+1 counter on Elenda, the Dusk Rose.$When Elenda dies, create X 1/1 white Vampire creature tokens with lifelink, where X is Elenda's power| +Huatli, Radiant Champion|Rivals of Ixalan|159|M|{2}{G}{W}|Legendary Planeswalker - Huatli|3|+1: Put a loyalty counter on Huatli, Radiant Champion for each creature you control.$-1: Target creature gets +X/+X until end of turn, where X is the number of creatures you control.$-8: You get an emblem with "Whenever a creature enters the battlefield under your control, you may draw a card."| Journey to Eternity|Rivals of Ixalan|160|R|{1}{B}{G}|Legendary Enchantment - Aura|||Enchant creature you control$When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control.| Atzal, Cave of Eternity|Rivals of Ixalan|160|R||Legendary Land|||(Transforms from Journey to Eternity.)${t}: Add one mana of any color to your mana pool.${3}{B}{G}, {t}: Return target creature card from your graveyard to the battlefield.| Kumena, Tyrant of Orzca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| +Legion Lieutenant|Rivals of Ixalan|163|U|{W}{B}|Creature - Vampire Knight|2|2|Other Vampires you control get +1/+1.| +Merfolk Mistbender|Rivals of Ixalan|164|U|{G}{U}|Creature - Merfolk Shaman|2|2|Other Merfolk you control get +1/+1.| Storm the Vault|Rivals of Ixalan|173|R|{2}{U}{R}|Legendary Enchantment|||Whenever one or more creatures you control deal combat damage to a player, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool."$At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault.| Vault of Catlacan|Rivals of Ixalan|173|R||Legendary Land|||(Transforms from Storm the Vault.)${T}: Add one mana of any color to your mana pool.${T}: Add {U} to your mana pool for each artifact you control.| -Awakened Amalgamation|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgamation's power and toughness are each equal to the number of lands you control with different names.| +Awakened Amalgam|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control.| Captain's Hook|Rivals of Ixalan|177|R|{3}|Artifact - Equipment|||Equipped creature gets +2/+0, has menace, and is a Pirate in addition to its other creature types.$Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent.$Equip {1}| Gleaming Barrier|Rivals of Ixalan|178|C|{2}|Artifact Creature - Wall|0|4|Defender$When Gleaming Barrier dies, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate planeswalkers' loyalty abilities.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.| From 204a602b364b28e87877c6dbe2202300ec4ef0f2 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 3 Jan 2018 07:43:15 +0400 Subject: [PATCH 43/54] Added old decklist files compatibility loading (free to change card numbers, names and codes, see #4332) --- .../cards/decks/importer/DckDeckImporter.java | 51 ++++++++++++++----- .../mage/cards/repository/CardRepository.java | 12 +++++ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java index 67837022b80..d5c591de534 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java @@ -67,22 +67,47 @@ public class DckDeckImporter extends DeckImporter { int count = Integer.parseInt(m.group(2)); String setCode = m.group(3); String cardNum = m.group(4); + String cardName = m.group(5); + + cardNum = cardNum == null ? "" : cardNum.trim(); + setCode = setCode == null ? "" : setCode.trim(); + cardName = cardName == null ? "" : cardName.trim(); + + // search priority: set/code -> name + // with bulletproof on card number or name changes DeckCardInfo deckCardInfo = null; - CardInfo cardInfo = CardRepository.instance.findCard(setCode, cardNum); - if (cardInfo == null) { - // Try alternate based on name - String cardName = m.group(5); - if (cardName != null && !cardName.isEmpty()) { - cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(cardName, false); - sbMessage.append("Could not find card '").append(cardName).append("' in set ").append(setCode).append(" of number ").append(cardNum).append(".\n"); - if (cardInfo != null) { - sbMessage.append("Made substitution of ").append(cardInfo.getCardNumber()).append(", ").append(cardInfo.getCard().getExpansionSetCode()).append(" instead.\n"); - } + + // search by number + CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum); + boolean wasOutdated = false; + if ((foundedCard != null) && !foundedCard.getName().equals(cardName)){ + sbMessage.append("Line ").append(lineCount).append(": ").append("founded outdated card number or name, will try to replace: ").append(line).append('\n'); + wasOutdated = true; + foundedCard = null; + } + + // search by name + if (foundedCard == null) { + if(!wasOutdated){ + sbMessage.append("Line ").append(lineCount).append(": ").append("can't find card by number, will try ro replace: ").append(line).append('\n'); + } + + if (!cardName.equals("")) { + foundedCard = CardRepository.instance.findPreferedCoreExpansionCard(cardName, false, setCode); + } + + if (foundedCard != null) { + sbMessage.append("Line ").append(lineCount).append(": ") + .append("replaced to [").append(foundedCard.getSetCode()).append(":").append(foundedCard.getCardNumberAsInt()).append("] ") + .append(foundedCard.getName()).append('\n'); + }else{ + sbMessage.append("Line ").append(lineCount).append(": ").append("ERROR, can't find card [").append(cardName).append("]").append('\n'); } } - if (cardInfo != null) { - deckCardInfo = new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode()); + + if (foundedCard != null) { + deckCardInfo = new DeckCardInfo(foundedCard.getName(), foundedCard.getCardNumber(), foundedCard.getSetCode()); } if (deckCardInfo != null) { for (int i = 0; i < count; i++) { @@ -92,8 +117,6 @@ public class DckDeckImporter extends DeckImporter { deckList.getSideboard().add(deckCardInfo); } } - } else { - sbMessage.append("Could not find card '").append("' at line ").append(lineCount).append(": ").append(line).append('\n'); } } else if (line.startsWith("NAME:")) { deckList.setName(line.substring(5, line.length())); diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index bb1e8eb74f4..96df863e88a 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -327,12 +327,19 @@ public enum CardRepository { } public CardInfo findPreferedCoreExpansionCard(String name, boolean caseInsensitive) { + return findPreferedCoreExpansionCard(name, caseInsensitive, null); + } + + + public CardInfo findPreferedCoreExpansionCard(String name, boolean caseInsensitive, String preferedSetCode) { + List cards; if (caseInsensitive) { cards = findCardsCaseInsensitive(name); } else { cards = findCards(name); } + if (!cards.isEmpty()) { Date lastReleaseDate = null; Date lastExpansionDate = null; @@ -340,6 +347,11 @@ public enum CardRepository { for (CardInfo cardinfo : cards) { ExpansionInfo set = ExpansionRepository.instance.getSetByCode(cardinfo.getSetCode()); if (set != null) { + + if ((preferedSetCode != null) && (preferedSetCode.equals(set.getCode()))){ + return cardinfo; + } + if ((set.getType() == SetType.EXPANSION || set.getType() == SetType.CORE) && (lastExpansionDate == null || set.getReleaseDate().after(lastExpansionDate))) { cardToUse = cardinfo; From 1a252e61a25448495e367e5eda7023f0c74acd2c Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 3 Jan 2018 09:10:39 +0400 Subject: [PATCH 44/54] Fixed #4311: deck editor can't load decks with cards cards from Masterpiece Series Amonkhet (MPS-AKH) --- .../main/java/mage/cards/decks/importer/DckDeckImporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java index d5c591de534..6f7a660a00c 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java @@ -49,7 +49,7 @@ public class DckDeckImporter extends DeckImporter { private static final Pattern layoutStackPattern = Pattern.compile("\\(([^)]*)\\)"); - private static final Pattern layoutStackEntryPattern = Pattern.compile("\\[(\\w+):(\\w+)]"); + private static final Pattern layoutStackEntryPattern = Pattern.compile("\\[(\\w+[^:]\\w+):(\\d+)]"); // [MPSAK1321:43],[MPSAKH:9],[MPS123-AKH:32],[MPS-13AKH:30],[MPS-AKH:49],[MPS-AKH:11] @Override protected void readLine(String line, DeckCardLists deckList) { From 32fb2507c34ca9cd0fd2ceadacfe55a14636e601 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 11:40:07 +0100 Subject: [PATCH 45/54] Some rework to Framework. --- .../src/mage/cards/a/AdunOakenshield.java | 10 ++-- .../mage/cards/a/ApprenticeNecromancer.java | 4 +- .../src/mage/cards/a/ArtisanOfKozilek.java | 11 ++-- .../src/mage/cards/b/BackFromTheBrink.java | 4 +- .../src/mage/cards/b/BetrayalOfFlesh.java | 8 +-- Mage.Sets/src/mage/cards/b/BodySnatcher.java | 7 ++- Mage.Sets/src/mage/cards/b/BreathOfLife.java | 7 +-- Mage.Sets/src/mage/cards/c/CabalSurgeon.java | 12 ++-- Mage.Sets/src/mage/cards/c/CadaverImp.java | 9 ++- Mage.Sets/src/mage/cards/c/CauldronDance.java | 5 +- .../src/mage/cards/c/CemeteryRecruitment.java | 9 ++- Mage.Sets/src/mage/cards/c/CorpseChurn.java | 6 +- Mage.Sets/src/mage/cards/c/CorpseLunge.java | 7 +-- .../src/mage/cards/c/CruelUltimatum.java | 3 +- Mage.Sets/src/mage/cards/d/DawnOfTheDead.java | 6 +- Mage.Sets/src/mage/cards/d/DefyDeath.java | 7 +-- .../src/mage/cards/d/DiabolicServitude.java | 15 +++-- Mage.Sets/src/mage/cards/d/Disentomb.java | 19 +++---- .../src/mage/cards/d/DisturbedBurial.java | 10 ++-- .../src/mage/cards/d/DoomedNecromancer.java | 10 ++-- Mage.Sets/src/mage/cards/d/DreadDefiler.java | 10 ++-- Mage.Sets/src/mage/cards/d/DreadReturn.java | 9 ++- .../src/mage/cards/e/EmeriaTheSkyRuin.java | 10 ++-- .../src/mage/cards/e/EntomberExarch.java | 9 +-- .../src/mage/cards/e/EvolutionCharm.java | 13 ++--- Mage.Sets/src/mage/cards/f/FalseDefeat.java | 6 +- .../src/mage/cards/f/FearsomeAwakening.java | 11 ++-- .../src/mage/cards/f/FortuitousFind.java | 6 +- Mage.Sets/src/mage/cards/f/FoulRenewal.java | 6 +- Mage.Sets/src/mage/cards/g/Genesis.java | 8 +-- .../src/mage/cards/g/GhoulcallersChant.java | 4 +- .../src/mage/cards/g/GodPharaohsGift.java | 7 +-- .../src/mage/cards/g/GolgariGuildmage.java | 12 ++-- Mage.Sets/src/mage/cards/g/GraveExchange.java | 9 +-- Mage.Sets/src/mage/cards/g/Gravedigger.java | 17 +++--- Mage.Sets/src/mage/cards/g/GrimDiscovery.java | 26 ++++----- Mage.Sets/src/mage/cards/g/GrimHarvest.java | 10 ++-- .../src/mage/cards/h/HauntedCrossroads.java | 6 +- Mage.Sets/src/mage/cards/h/HeadlessSkaab.java | 6 +- .../src/mage/cards/h/HellsCaretaker.java | 14 ++--- .../mage/cards/h/HuaTuoHonoredPhysician.java | 6 +- Mage.Sets/src/mage/cards/k/KarmicGuide.java | 6 +- .../src/mage/cards/k/KolaghansCommand.java | 26 ++++----- Mage.Sets/src/mage/cards/l/LifeDeath.java | 4 +- .../mage/cards/l/LilianaDeathsMajesty.java | 4 +- .../src/mage/cards/l/LilianaTheLastHope.java | 6 +- .../src/mage/cards/m/MakeshiftMannequin.java | 6 +- .../src/mage/cards/m/MakeshiftMauler.java | 6 +- .../src/mage/cards/m/MarchOfTheDrowned.java | 4 +- .../src/mage/cards/m/MidnightRecovery.java | 11 ++-- .../src/mage/cards/m/MidnightRitual.java | 10 ++-- Mage.Sets/src/mage/cards/m/MorgueBurst.java | 6 +- Mage.Sets/src/mage/cards/m/MortuaryMire.java | 6 +- .../src/mage/cards/n/NecromanticThirst.java | 14 ++--- Mage.Sets/src/mage/cards/n/NullCaller.java | 6 +- .../src/mage/cards/o/OversoldCemetery.java | 7 ++- .../src/mage/cards/p/PhyrexianDelver.java | 8 +-- .../mage/cards/p/PhyrexianReclamation.java | 7 +-- Mage.Sets/src/mage/cards/p/PitKeeper.java | 13 +++-- .../src/mage/cards/p/PostmortemLunge.java | 3 +- .../src/mage/cards/p/PulsemageAdvocate.java | 9 +-- Mage.Sets/src/mage/cards/r/RaiseDead.java | 10 +--- .../src/mage/cards/r/RavosSoultender.java | 6 +- .../src/mage/cards/r/ReapingTheGraves.java | 6 +- Mage.Sets/src/mage/cards/r/Recover.java | 9 +-- .../src/mage/cards/r/RelentlessSkaabs.java | 6 +- .../src/mage/cards/r/RememberTheFallen.java | 56 +++---------------- Mage.Sets/src/mage/cards/r/Repurpose.java | 6 +- .../src/mage/cards/r/ResourcefulReturn.java | 7 +-- .../src/mage/cards/r/RestlessDreams.java | 12 ++-- Mage.Sets/src/mage/cards/r/Resurrection.java | 7 +-- .../src/mage/cards/r/ReturnToBattle.java | 6 +- .../src/mage/cards/r/RevivingMelody.java | 11 ++-- .../src/mage/cards/r/ReyaDawnbringer.java | 6 +- .../mage/cards/s/SheoldredWhisperingOne.java | 3 +- .../src/mage/cards/s/SibsigMuckdraggers.java | 6 +- Mage.Sets/src/mage/cards/s/SkaabGoliath.java | 6 +- Mage.Sets/src/mage/cards/s/SkaabRuinator.java | 15 +++-- Mage.Sets/src/mage/cards/s/SoulExchange.java | 19 ++++--- .../src/mage/cards/s/SoulManipulation.java | 20 +++---- Mage.Sets/src/mage/cards/s/SoulSeparator.java | 6 +- .../src/mage/cards/s/SoullessRevival.java | 10 ++-- .../src/mage/cards/s/StitchTogether.java | 6 +- Mage.Sets/src/mage/cards/s/StitchedDrake.java | 6 +- .../src/mage/cards/s/StrandsOfNight.java | 9 ++- .../src/mage/cards/s/SuddenReclamation.java | 6 +- .../mage/cards/s/SwordOfLightAndShadow.java | 6 +- .../src/mage/cards/t/TorturedExistence.java | 7 ++- Mage.Sets/src/mage/cards/t/TriassicEgg.java | 17 +++--- Mage.Sets/src/mage/cards/u/UnburialRites.java | 7 +-- Mage.Sets/src/mage/cards/u/Undertaker.java | 10 ++-- .../src/mage/cards/w/WarrenPilferers.java | 6 +- Mage.Sets/src/mage/cards/w/WhipOfErebos.java | 5 +- .../src/mage/cards/w/WildwoodRebirth.java | 7 +-- Mage.Sets/src/mage/cards/w/Woebearer.java | 6 +- .../src/mage/cards/w/WretchedConfluence.java | 18 +++--- Mage.Sets/src/mage/cards/z/Zombify.java | 7 +-- .../effects/AuraReplacementEffect.java | 9 ++- ...lefieldUnderYourControlAttachedEffect.java | 11 +++- Mage/src/main/java/mage/constants/Zone.java | 6 +- .../main/java/mage/filter/StaticFilters.java | 5 +- 101 files changed, 426 insertions(+), 497 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AdunOakenshield.java b/Mage.Sets/src/mage/cards/a/AdunOakenshield.java index d219f5def73..95aacbc1ee1 100644 --- a/Mage.Sets/src/mage/cards/a/AdunOakenshield.java +++ b/Mage.Sets/src/mage/cards/a/AdunOakenshield.java @@ -40,7 +40,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -49,10 +49,8 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class AdunOakenshield extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public AdunOakenshield(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -61,8 +59,8 @@ public class AdunOakenshield extends CardImpl { this.toughness = new MageInt(2); //{B}{R}{G}, {T}: Return target creature card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(),new ManaCostsImpl("{B}{R}{G}")); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{B}{R}{G}")); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ApprenticeNecromancer.java b/Mage.Sets/src/mage/cards/a/ApprenticeNecromancer.java index a8030c3c77e..77e71fb4ef9 100644 --- a/Mage.Sets/src/mage/cards/a/ApprenticeNecromancer.java +++ b/Mage.Sets/src/mage/cards/a/ApprenticeNecromancer.java @@ -45,7 +45,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -70,7 +70,7 @@ public class ApprenticeNecromancer extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ApprenticeNecromancerEffect(), new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArtisanOfKozilek.java b/Mage.Sets/src/mage/cards/a/ArtisanOfKozilek.java index 54d754c1db1..18dedcc0144 100644 --- a/Mage.Sets/src/mage/cards/a/ArtisanOfKozilek.java +++ b/Mage.Sets/src/mage/cards/a/ArtisanOfKozilek.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.a; import java.util.UUID; @@ -38,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,20 +46,20 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class ArtisanOfKozilek extends CardImpl { - public ArtisanOfKozilek (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{9}"); + public ArtisanOfKozilek(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{9}"); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(10); this.toughness = new MageInt(9); // When you cast Artisan of Kozilek, you may return target creature card from your graveyard to the battlefield. Ability ability = new CastSourceTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // Annihilator 2 this.addAbility(new AnnihilatorAbility(2)); } - public ArtisanOfKozilek (final ArtisanOfKozilek card) { + public ArtisanOfKozilek(final ArtisanOfKozilek card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java b/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java index c056da0ca29..6e92e76df4d 100644 --- a/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java +++ b/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java @@ -40,7 +40,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.Target; @@ -76,7 +76,7 @@ public class BackFromTheBrink extends CardImpl { class BackFromTheBrinkCost extends CostImpl { public BackFromTheBrinkCost() { - Target target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); this.addTarget(target); this.text = "Exile a creature card from your graveyard and pay its mana cost"; diff --git a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java index 66f23cef42d..07dc06d0b4d 100644 --- a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java +++ b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java @@ -36,8 +36,8 @@ import mage.abilities.keyword.EntwineAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; @@ -45,12 +45,12 @@ import mage.target.common.TargetCreaturePermanent; /** * * @author LoneFox - + * */ public class BetrayalOfFlesh extends CardImpl { public BetrayalOfFlesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{B}"); // Choose one - this.getSpellAbility().getModes().setMinModes(1); @@ -61,7 +61,7 @@ public class BetrayalOfFlesh extends CardImpl { // or return target creature card from your graveyard to the battlefield. Mode mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); // Entwine-Sacrifice three lands. this.addAbility(new EntwineAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, new FilterControlledLandPermanent("three lands"), true)))); diff --git a/Mage.Sets/src/mage/cards/b/BodySnatcher.java b/Mage.Sets/src/mage/cards/b/BodySnatcher.java index 0a0d9130356..56355cef643 100644 --- a/Mage.Sets/src/mage/cards/b/BodySnatcher.java +++ b/Mage.Sets/src/mage/cards/b/BodySnatcher.java @@ -41,6 +41,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInYourGraveyard; @@ -52,20 +53,20 @@ import mage.target.common.TargetCardInYourGraveyard; public class BodySnatcher extends CardImpl { public BodySnatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.MINION); this.power = new MageInt(2); this.toughness = new MageInt(2); // When Body Snatcher enters the battlefield, exile it unless you discard a creature card. this.addAbility(new EntersBattlefieldTriggeredAbility(new ExileSourceUnlessPaysEffect(new DiscardTargetCost(new TargetCardInHand(new FilterCreatureCard("a creature card")))))); - + // When Body Snatcher dies, exile Body Snatcher and return target creature card from your graveyard to the battlefield. Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setText("and return target creature card from your graveyard to the battlefield"); Ability ability = new DiesTriggeredAbility(new ExileSourceEffect(), false); ability.addEffect(effect); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreathOfLife.java b/Mage.Sets/src/mage/cards/b/BreathOfLife.java index 5ebb238770d..89707a5ef25 100644 --- a/Mage.Sets/src/mage/cards/b/BreathOfLife.java +++ b/Mage.Sets/src/mage/cards/b/BreathOfLife.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,12 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class BreathOfLife extends CardImpl { public BreathOfLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public BreathOfLife(final BreathOfLife card) { diff --git a/Mage.Sets/src/mage/cards/c/CabalSurgeon.java b/Mage.Sets/src/mage/cards/c/CabalSurgeon.java index 48413cde794..c53b25976e0 100644 --- a/Mage.Sets/src/mage/cards/c/CabalSurgeon.java +++ b/Mage.Sets/src/mage/cards/c/CabalSurgeon.java @@ -41,7 +41,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -50,21 +50,19 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class CabalSurgeon extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public CabalSurgeon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.MINION); this.power = new MageInt(2); this.toughness = new MageInt(1); // {2}{B}{B}, {tap}, Exile two cards from your graveyard: Return target creature card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(),new ManaCostsImpl("{2}{B}{B}")); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{2}{B}{B}")); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addCost(new TapSourceCost()); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, new FilterCard("cards from your graveyard")))); - this.addAbility(ability); + this.addAbility(ability); } public CabalSurgeon(final CabalSurgeon card) { diff --git a/Mage.Sets/src/mage/cards/c/CadaverImp.java b/Mage.Sets/src/mage/cards/c/CadaverImp.java index 6e03cd8b45c..67bc621c017 100644 --- a/Mage.Sets/src/mage/cards/c/CadaverImp.java +++ b/Mage.Sets/src/mage/cards/c/CadaverImp.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,15 +47,18 @@ import mage.target.common.TargetCardInYourGraveyard; public class CadaverImp extends CardImpl { public CadaverImp(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.subtype.add(SubType.IMP); this.power = new MageInt(1); this.toughness = new MageInt(1); + // Flying this.addAbility(FlyingAbility.getInstance()); + + // When Cadaver Imp enters the battlefield, you may return target creature card from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CauldronDance.java b/Mage.Sets/src/mage/cards/c/CauldronDance.java index 3f4815410b7..f73c8b083a3 100644 --- a/Mage.Sets/src/mage/cards/c/CauldronDance.java +++ b/Mage.Sets/src/mage/cards/c/CauldronDance.java @@ -42,6 +42,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; @@ -56,14 +57,14 @@ import mage.target.targetpointer.FixedTarget; public class CauldronDance extends CardImpl { public CauldronDance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}{R}"); // Cast Cauldron Dance only during combat. this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT)); // Return target creature card from your graveyard to the battlefield. That creature gains haste. Return it to your hand at the beginning of the next end step. this.getSpellAbility().addEffect(new CauldronDanceReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // You may put a creature card from your hand onto the battlefield. That creature gains haste. Its controller sacrifices it at the beginning of the next end step. this.getSpellAbility().addEffect(new CauldronDancePutCreatureFromHandOntoBattlefieldEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryRecruitment.java b/Mage.Sets/src/mage/cards/c/CemeteryRecruitment.java index 9d754cd83b2..0363af2e674 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryRecruitment.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryRecruitment.java @@ -27,6 +27,7 @@ */ package mage.cards.c; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -36,13 +37,11 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * * @author fireshoes @@ -50,11 +49,11 @@ import java.util.UUID; public class CemeteryRecruitment extends CardImpl { public CemeteryRecruitment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Return target creature card from your graveyard to your hand. If it's a Zombie card, draw a card. this.getSpellAbility().addEffect(new CemeteryRecruitmentEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public CemeteryRecruitment(final CemeteryRecruitment card) { diff --git a/Mage.Sets/src/mage/cards/c/CorpseChurn.java b/Mage.Sets/src/mage/cards/c/CorpseChurn.java index 0a95de02427..31bbba9bf88 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseChurn.java +++ b/Mage.Sets/src/mage/cards/c/CorpseChurn.java @@ -37,7 +37,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class CorpseChurn extends CardImpl { public CorpseChurn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Put the top three cards of your library into your graveyard, then you may return a creature card from your graveyard to your hand. getSpellAbility().addEffect(new PutTopCardOfLibraryIntoGraveControllerEffect(3)); @@ -88,7 +88,7 @@ class CorpseChurnEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) diff --git a/Mage.Sets/src/mage/cards/c/CorpseLunge.java b/Mage.Sets/src/mage/cards/c/CorpseLunge.java index 304a0d072f0..bc7469e59d4 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseLunge.java +++ b/Mage.Sets/src/mage/cards/c/CorpseLunge.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; @@ -50,11 +50,10 @@ import mage.target.common.TargetCreaturePermanent; public class CorpseLunge extends CardImpl { public CorpseLunge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // As an additional cost to cast Corpse Lunge, exile a creature card from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); // Corpse Lunge deals damage equal to the exiled card's power to target creature. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new CorpseLungeEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java index 2162131f563..f9c94d3ddb2 100644 --- a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java @@ -42,7 +42,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -101,7 +100,7 @@ class CruelUltimatumEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card == null) { diff --git a/Mage.Sets/src/mage/cards/d/DawnOfTheDead.java b/Mage.Sets/src/mage/cards/d/DawnOfTheDead.java index 6bbd8296975..14e4b1db012 100644 --- a/Mage.Sets/src/mage/cards/d/DawnOfTheDead.java +++ b/Mage.Sets/src/mage/cards/d/DawnOfTheDead.java @@ -42,7 +42,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -56,7 +56,7 @@ import mage.target.targetpointer.FixedTarget; public class DawnOfTheDead extends CardImpl { public DawnOfTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}{B}"); // At the beginning of your upkeep, you lose 1 life. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(1), TargetController.YOU, false)); @@ -64,7 +64,7 @@ public class DawnOfTheDead extends CardImpl { // At the beginning of your upkeep, you may return target creature card from your graveyard to the battlefield. // That creature gains haste until end of turn. Exile it at the beginning of the next end step. Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DawnOfTheDeadEffect(), TargetController.YOU, true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DefyDeath.java b/Mage.Sets/src/mage/cards/d/DefyDeath.java index b386c96919a..03d0f46047b 100644 --- a/Mage.Sets/src/mage/cards/d/DefyDeath.java +++ b/Mage.Sets/src/mage/cards/d/DefyDeath.java @@ -37,7 +37,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; @@ -49,13 +49,12 @@ import mage.target.common.TargetCardInYourGraveyard; public class DefyDeath extends CardImpl { public DefyDeath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}"); // Return target creature card from your graveyard to the battlefield. If it's an Angel, put two +1/+1 counters on it. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); this.getSpellAbility().addEffect(new DefyDeathEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public DefyDeath(final DefyDeath card) { diff --git a/Mage.Sets/src/mage/cards/d/DiabolicServitude.java b/Mage.Sets/src/mage/cards/d/DiabolicServitude.java index b07ed4e620c..e89349e8814 100644 --- a/Mage.Sets/src/mage/cards/d/DiabolicServitude.java +++ b/Mage.Sets/src/mage/cards/d/DiabolicServitude.java @@ -44,7 +44,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -59,12 +59,11 @@ import mage.target.targetpointer.FixedTarget; public class DiabolicServitude extends CardImpl { public DiabolicServitude(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); // When Diabolic Servitude enters the battlefield, return target creature card from your graveyard to the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new DiabolicServitudeReturnCreatureEffect()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // When the creature put onto the battlefield with Diabolic Servitude dies, exile it and return Diabolic Servitude to its owner's hand. @@ -138,10 +137,10 @@ class DiabolicServitudeCreatureDiesTriggeredAbility extends TriggeredAbilityImpl @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent)event).isDiesEvent()) { + if (((ZoneChangeEvent) event).isDiesEvent()) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; Object object = game.getState().getValue(getSourceId().toString() + "returnedCreature"); - if ((object instanceof MageObjectReference) && ((MageObjectReference)object).refersTo(zEvent.getTarget(), game)) { + if ((object instanceof MageObjectReference) && ((MageObjectReference) object).refersTo(zEvent.getTarget(), game)) { return true; } } @@ -175,7 +174,7 @@ class DiabolicServitudeExileCreatureEffect extends OneShotEffect { Object object = game.getState().getValue(source.getSourceId().toString() + "returnedCreature"); if ((object instanceof MageObjectReference)) { Effect effect = new ExileTargetEffect(); - effect.setTargetPointer(new FixedTarget(((MageObjectReference)object).getSourceId())); + effect.setTargetPointer(new FixedTarget(((MageObjectReference) object).getSourceId())); effect.apply(game, source); return new ReturnToHandSourceEffect(true).apply(game, source); } @@ -204,7 +203,7 @@ class DiabolicServitudeSourceLeftBattlefieldEffect extends OneShotEffect { Object object = game.getState().getValue(source.getSourceId().toString() + "returnedCreature"); if ((object instanceof MageObjectReference)) { Effect effect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); - effect.setTargetPointer(new FixedTarget(((MageObjectReference)object).getSourceId())); + effect.setTargetPointer(new FixedTarget(((MageObjectReference) object).getSourceId())); effect.apply(game, source); } return false; diff --git a/Mage.Sets/src/mage/cards/d/Disentomb.java b/Mage.Sets/src/mage/cards/d/Disentomb.java index 07e6bcf320c..f6e3a2a892a 100644 --- a/Mage.Sets/src/mage/cards/d/Disentomb.java +++ b/Mage.Sets/src/mage/cards/d/Disentomb.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.d; import java.util.UUID; @@ -33,7 +32,7 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,12 +41,10 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class Disentomb extends CardImpl { - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public Disentomb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DisturbedBurial.java b/Mage.Sets/src/mage/cards/d/DisturbedBurial.java index 8b80ba9c394..6e8482f1ae7 100644 --- a/Mage.Sets/src/mage/cards/d/DisturbedBurial.java +++ b/Mage.Sets/src/mage/cards/d/DisturbedBurial.java @@ -33,7 +33,7 @@ import mage.abilities.keyword.BuybackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -41,16 +41,14 @@ import mage.target.common.TargetCardInYourGraveyard; * @author fireshoes */ public class DisturbedBurial extends CardImpl { - - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); public DisturbedBurial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Buyback {3} - this.addAbility(new BuybackAbility("{3}")); + this.addAbility(new BuybackAbility("{3}")); // Return target creature card from your graveyard to your hand. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DoomedNecromancer.java b/Mage.Sets/src/mage/cards/d/DoomedNecromancer.java index 55f0a60aac3..7bc722a4fb9 100644 --- a/Mage.Sets/src/mage/cards/d/DoomedNecromancer.java +++ b/Mage.Sets/src/mage/cards/d/DoomedNecromancer.java @@ -38,10 +38,10 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ColoredManaSymbol; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -51,7 +51,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class DoomedNecromancer extends CardImpl { public DoomedNecromancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.subtype.add(SubType.MERCENARY); @@ -63,9 +63,9 @@ public class DoomedNecromancer extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); - + } public DoomedNecromancer(final DoomedNecromancer card) { diff --git a/Mage.Sets/src/mage/cards/d/DreadDefiler.java b/Mage.Sets/src/mage/cards/d/DreadDefiler.java index 232f791f903..a1df325e4cf 100644 --- a/Mage.Sets/src/mage/cards/d/DreadDefiler.java +++ b/Mage.Sets/src/mage/cards/d/DreadDefiler.java @@ -40,10 +40,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -56,17 +56,17 @@ import mage.target.common.TargetOpponent; public class DreadDefiler extends CardImpl { public DreadDefiler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}"); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(6); this.toughness = new MageInt(8); // Devoid this.addAbility(new DevoidAbility(this.color)); - + // {3}{C}, Exile a creature card from your graveyard: Target opponent loses life equal to the exiled card's power. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DreadDefilerEffect(), new ManaCostsImpl("{3}{C}")); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DreadReturn.java b/Mage.Sets/src/mage/cards/d/DreadReturn.java index 085e8c89596..9feb2b51d79 100644 --- a/Mage.Sets/src/mage/cards/d/DreadReturn.java +++ b/Mage.Sets/src/mage/cards/d/DreadReturn.java @@ -35,8 +35,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; @@ -47,14 +47,13 @@ import mage.target.common.TargetControlledCreaturePermanent; public class DreadReturn extends CardImpl { public DreadReturn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Flashback-Sacrifice three creatures. - this.addAbility(new FlashbackAbility(new SacrificeTargetCost(new TargetControlledCreaturePermanent(3,3,new FilterControlledCreaturePermanent("three creatures"),true)), TimingRule.SORCERY)); + this.addAbility(new FlashbackAbility(new SacrificeTargetCost(new TargetControlledCreaturePermanent(3, 3, new FilterControlledCreaturePermanent("three creatures"), true)), TimingRule.SORCERY)); } public DreadReturn(final DreadReturn card) { diff --git a/Mage.Sets/src/mage/cards/e/EmeriaTheSkyRuin.java b/Mage.Sets/src/mage/cards/e/EmeriaTheSkyRuin.java index aa73fef0f2e..cff964f7a61 100644 --- a/Mage.Sets/src/mage/cards/e/EmeriaTheSkyRuin.java +++ b/Mage.Sets/src/mage/cards/e/EmeriaTheSkyRuin.java @@ -37,7 +37,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; @@ -48,12 +48,12 @@ import mage.target.common.TargetCardInYourGraveyard; /** * * @author North - * @author LevelX - changed to checkInterveningIfClause + * @author LevelX - changed to checkInterveningIfClause */ public class EmeriaTheSkyRuin extends CardImpl { public EmeriaTheSkyRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Emeria, the Sky Ruin enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); @@ -83,7 +83,7 @@ class EmeriaTheSkyRuinTriggeredAbility extends TriggeredAbilityImpl { public EmeriaTheSkyRuinTriggeredAbility() { super(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), true); - this.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public EmeriaTheSkyRuinTriggeredAbility(final EmeriaTheSkyRuinTriggeredAbility ability) { @@ -107,7 +107,7 @@ class EmeriaTheSkyRuinTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - return game.getBattlefield().countAll(filter, this.controllerId, game) >= 7; + return game.getBattlefield().countAll(filter, this.controllerId, game) >= 7; } @Override diff --git a/Mage.Sets/src/mage/cards/e/EntomberExarch.java b/Mage.Sets/src/mage/cards/e/EntomberExarch.java index 13d6ff963cd..25654c6fa6d 100644 --- a/Mage.Sets/src/mage/cards/e/EntomberExarch.java +++ b/Mage.Sets/src/mage/cards/e/EntomberExarch.java @@ -38,11 +38,11 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; @@ -58,7 +58,7 @@ import mage.target.common.TargetOpponent; public class EntomberExarch extends CardImpl { public EntomberExarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); @@ -66,7 +66,7 @@ public class EntomberExarch extends CardImpl { // When Entomber Exarch enters the battlefield, choose one - Return target creature card from your graveyard to your hand; or target opponent reveals his or her hand, you choose a noncreature card from it, then that player discards that card. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); Mode mode = new Mode(); mode.getEffects().add(new EntomberExarchEffect()); mode.getTargets().add(new TargetOpponent()); @@ -85,6 +85,7 @@ public class EntomberExarch extends CardImpl { } class EntomberExarchEffect extends OneShotEffect { + private static final FilterCard filter = new FilterCard("noncreature card"); static { diff --git a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java index b3b4890d468..59d192d18df 100644 --- a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java +++ b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java @@ -37,7 +37,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -49,21 +48,19 @@ import java.util.UUID; * @author fireshoes */ public class EvolutionCharm extends CardImpl { - - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); public EvolutionCharm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Choose one - Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library; this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, StaticFilters.FILTER_BASIC_LAND_CARD), true, true)); - - // or return target creature card from your graveyard to your hand; + + // or return target creature card from your graveyard to your hand; Mode mode = new Mode(); mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(filter)); + mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addMode(mode); - + // or target creature gains flying until end of turn. mode = new Mode(); mode.getEffects().add(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/f/FalseDefeat.java b/Mage.Sets/src/mage/cards/f/FalseDefeat.java index ab2810f667b..df23b4f346e 100644 --- a/Mage.Sets/src/mage/cards/f/FalseDefeat.java +++ b/Mage.Sets/src/mage/cards/f/FalseDefeat.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,11 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class FalseDefeat extends CardImpl { public FalseDefeat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public FalseDefeat(final FalseDefeat card) { diff --git a/Mage.Sets/src/mage/cards/f/FearsomeAwakening.java b/Mage.Sets/src/mage/cards/f/FearsomeAwakening.java index 5239be70c2c..71e9aced198 100644 --- a/Mage.Sets/src/mage/cards/f/FearsomeAwakening.java +++ b/Mage.Sets/src/mage/cards/f/FearsomeAwakening.java @@ -27,6 +27,7 @@ */ package mage.cards.f; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; @@ -36,13 +37,11 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * * @author fireshoes @@ -50,12 +49,12 @@ import java.util.UUID; public class FearsomeAwakening extends CardImpl { public FearsomeAwakening(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Return target creature card from your graveyard to the battlefield. If it's a Dragon, put two +1/+1 counters on it. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); this.getSpellAbility().addEffect(new FearsomeAwakeningEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public FearsomeAwakening(final FearsomeAwakening card) { @@ -93,4 +92,4 @@ class FearsomeAwakeningEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/f/FortuitousFind.java b/Mage.Sets/src/mage/cards/f/FortuitousFind.java index 37d9ced7371..6bd6b437d70 100644 --- a/Mage.Sets/src/mage/cards/f/FortuitousFind.java +++ b/Mage.Sets/src/mage/cards/f/FortuitousFind.java @@ -33,8 +33,8 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; /** @@ -44,7 +44,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class FortuitousFind extends CardImpl { public FortuitousFind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Choose one or both — this.getSpellAbility().getModes().setMinModes(1); @@ -57,7 +57,7 @@ public class FortuitousFind extends CardImpl { // or Return target creature card from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FoulRenewal.java b/Mage.Sets/src/mage/cards/f/FoulRenewal.java index e5080f88c23..88f87dd0764 100644 --- a/Mage.Sets/src/mage/cards/f/FoulRenewal.java +++ b/Mage.Sets/src/mage/cards/f/FoulRenewal.java @@ -39,7 +39,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -53,11 +53,11 @@ import mage.target.targetpointer.FixedTarget; public class FoulRenewal extends CardImpl { public FoulRenewal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); // Return target creature card from your graveyard to your hand. Target creature gets -X/-X until end of turn, where X is the toughness of the card returned this way. this.getSpellAbility().addEffect(new FoulRenewalEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/g/Genesis.java b/Mage.Sets/src/mage/cards/g/Genesis.java index 3e4fbe07d43..26eac63a58c 100644 --- a/Mage.Sets/src/mage/cards/g/Genesis.java +++ b/Mage.Sets/src/mage/cards/g/Genesis.java @@ -40,7 +40,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -50,7 +50,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class Genesis extends CardImpl { public Genesis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); this.subtype.add(SubType.INCARNATION); this.power = new MageInt(4); @@ -58,8 +58,8 @@ public class Genesis extends CardImpl { // At the beginning of your upkeep, if Genesis is in your graveyard, you may pay {2}{G}. If you do, return target creature card from your graveyard to your hand. Ability ability = new BeginningOfUpkeepTriggeredAbility( - Zone.GRAVEYARD, new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{2}{G}")),TargetController.YOU, false, false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + Zone.GRAVEYARD, new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{2}{G}")), TargetController.YOU, false, false); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java index 8246863f23f..b5971dab4bc 100644 --- a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java +++ b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java @@ -35,7 +35,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInYourGraveyard; @@ -56,7 +56,7 @@ public class GhoulcallersChant extends CardImpl { // Choose one - Return target creature card from your graveyard to your hand this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // or return two target Zombie cards from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java b/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java index 6f7c8d0cccf..47f3e65ab11 100644 --- a/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java +++ b/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java @@ -45,7 +45,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; @@ -80,7 +80,6 @@ public class GodPharaohsGift extends CardImpl { class GodPharaohsGiftEffect extends OneShotEffect { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); private final UUID exileId = UUID.randomUUID(); public GodPharaohsGiftEffect() { @@ -102,9 +101,9 @@ class GodPharaohsGiftEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (!controller.getGraveyard().getCards(filter, game).isEmpty() + if (!controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD, game).isEmpty() && controller.choose(Outcome.PutCreatureInPlay, target, source.getId(), game)) { Card cardChosen = game.getCard(target.getFirstTarget()); if (cardChosen != null diff --git a/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java b/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java index 2398c625ffe..b6f965c0766 100644 --- a/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java +++ b/Mage.Sets/src/mage/cards/g/GolgariGuildmage.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.g; import java.util.UUID; @@ -42,7 +41,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -53,24 +52,23 @@ import mage.target.common.TargetCreaturePermanent; */ public class GolgariGuildmage extends CardImpl { - public GolgariGuildmage (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B/G}{B/G}"); + public GolgariGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B/G}{B/G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(2); this.toughness = new MageInt(2); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{4}{B}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{4}{G}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } - public GolgariGuildmage (final GolgariGuildmage card) { + public GolgariGuildmage(final GolgariGuildmage card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/g/GraveExchange.java b/Mage.Sets/src/mage/cards/g/GraveExchange.java index e3445e96766..2b3f23f780e 100644 --- a/Mage.Sets/src/mage/cards/g/GraveExchange.java +++ b/Mage.Sets/src/mage/cards/g/GraveExchange.java @@ -35,8 +35,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -51,15 +51,12 @@ import mage.target.common.TargetControlledPermanent; */ public class GraveExchange extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public GraveExchange(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Target player sacrifices a creature. this.getSpellAbility().addEffect(new GraveExchangeEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/g/Gravedigger.java b/Mage.Sets/src/mage/cards/g/Gravedigger.java index 0147ecc0faf..45b0e8a4db3 100644 --- a/Mage.Sets/src/mage/cards/g/Gravedigger.java +++ b/Mage.Sets/src/mage/cards/g/Gravedigger.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,12 +20,11 @@ * 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; @@ -37,7 +36,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,14 +46,14 @@ import mage.target.common.TargetCardInYourGraveyard; public class Gravedigger extends CardImpl { public Gravedigger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); this.toughness = new MageInt(2); Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java index be6dc357c5d..b1dd81ecdce 100644 --- a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java +++ b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java @@ -1,4 +1,4 @@ - /* +/* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -27,15 +27,15 @@ */ package mage.cards.g; - import java.util.UUID; - import mage.abilities.Mode; - import mage.abilities.effects.common.ReturnToHandTargetEffect; - import mage.cards.CardImpl; - import mage.cards.CardSetInfo; - import mage.constants.CardType; - import mage.filter.common.FilterCreatureCard; - import mage.filter.common.FilterLandCard; - import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; +import mage.abilities.Mode; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; +import mage.target.common.TargetCardInYourGraveyard; /** * @@ -43,19 +43,17 @@ package mage.cards.g; */ public class GrimDiscovery extends CardImpl { - private static final FilterCreatureCard filterCreatureCard = new FilterCreatureCard("creature card from your graveyard"); private static final FilterLandCard filterLandCard = new FilterLandCard("land card from your graveyard"); public GrimDiscovery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Choose one or both - this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); // Return target creature card from your graveyard to your hand; this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCreatureCard)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // and/or return target land card from your graveyard to your hand. Mode mode1 = new Mode(); mode1.getEffects().add(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/g/GrimHarvest.java b/Mage.Sets/src/mage/cards/g/GrimHarvest.java index 4ed7a3d4137..9a963c8983b 100644 --- a/Mage.Sets/src/mage/cards/g/GrimHarvest.java +++ b/Mage.Sets/src/mage/cards/g/GrimHarvest.java @@ -34,7 +34,7 @@ import mage.abilities.keyword.RecoverAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,16 +42,14 @@ import mage.target.common.TargetCardInYourGraveyard; * @author fireshoes */ public class GrimHarvest extends CardImpl { - - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); public GrimHarvest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Return target creature card from your graveyard to your hand. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - + // Recover {2}{B} this.addAbility(new RecoverAbility(new ManaCostsImpl("{2}{B}"), this)); } diff --git a/Mage.Sets/src/mage/cards/h/HauntedCrossroads.java b/Mage.Sets/src/mage/cards/h/HauntedCrossroads.java index acd4004f2da..be51ef916d3 100644 --- a/Mage.Sets/src/mage/cards/h/HauntedCrossroads.java +++ b/Mage.Sets/src/mage/cards/h/HauntedCrossroads.java @@ -36,7 +36,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -46,11 +46,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class HauntedCrossroads extends CardImpl { public HauntedCrossroads(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); // {B}: Put target creature card from your graveyard on top of your library. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new ManaCostsImpl("{B}")); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HeadlessSkaab.java b/Mage.Sets/src/mage/cards/h/HeadlessSkaab.java index 385aa312abd..539d4293f1c 100644 --- a/Mage.Sets/src/mage/cards/h/HeadlessSkaab.java +++ b/Mage.Sets/src/mage/cards/h/HeadlessSkaab.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -45,7 +45,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class HeadlessSkaab extends CardImpl { public HeadlessSkaab(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WARRIOR); @@ -53,7 +53,7 @@ public class HeadlessSkaab extends CardImpl { this.toughness = new MageInt(6); // As an additional cost to cast Headless Skaab, exile a creature card from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); // Headless Skaab enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); } diff --git a/Mage.Sets/src/mage/cards/h/HellsCaretaker.java b/Mage.Sets/src/mage/cards/h/HellsCaretaker.java index 428ed7b6eb5..e88ed7a1749 100644 --- a/Mage.Sets/src/mage/cards/h/HellsCaretaker.java +++ b/Mage.Sets/src/mage/cards/h/HellsCaretaker.java @@ -38,10 +38,10 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; @@ -52,18 +52,18 @@ import mage.target.common.TargetControlledCreaturePermanent; public class HellsCaretaker extends CardImpl { public HellsCaretaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}, Sacrifice a creature: Return target creature card from your graveyard to the battlefield. Activate this ability only during your upkeep. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new ReturnFromGraveyardToBattlefieldTargetEffect(), - new TapSourceCost(), + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new ReturnFromGraveyardToBattlefieldTargetEffect(), + new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP), null); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent())); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java b/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java index 785dcb8ac71..dcdb94eeef4 100644 --- a/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java +++ b/Mage.Sets/src/mage/cards/h/HuaTuoHonoredPhysician.java @@ -40,7 +40,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -50,7 +50,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class HuaTuoHonoredPhysician extends CardImpl { public HuaTuoHonoredPhysician(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); @@ -59,7 +59,7 @@ public class HuaTuoHonoredPhysician extends CardImpl { // {tap}: Put target creature card from your graveyard on top of your library. Activate this ability only during your turn, before attackers are declared. Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.instance); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KarmicGuide.java b/Mage.Sets/src/mage/cards/k/KarmicGuide.java index 0de8cdfe901..1fe2f7af535 100644 --- a/Mage.Sets/src/mage/cards/k/KarmicGuide.java +++ b/Mage.Sets/src/mage/cards/k/KarmicGuide.java @@ -40,7 +40,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -50,7 +50,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class KarmicGuide extends CardImpl { public KarmicGuide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ANGEL); this.subtype.add(SubType.SPIRIT); @@ -64,7 +64,7 @@ public class KarmicGuide extends CardImpl { this.addAbility(new EchoAbility("{3}{W}{W}")); // When Karmic Guide enters the battlefield, return target creature card from your graveyard to the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java index 638f37e07f5..7ac3119ec1a 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java +++ b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetPermanent; import mage.target.TargetPlayer; @@ -49,7 +49,7 @@ import mage.target.common.TargetCreatureOrPlayer; * @author fireshoes */ public class KolaghansCommand extends CardImpl { - + private static final FilterPermanent filter = new FilterPermanent("artifact"); static { @@ -57,33 +57,33 @@ public class KolaghansCommand extends CardImpl { } public KolaghansCommand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{R}"); - // Choose two - + // Choose two - this.getSpellAbility().getModes().setMinModes(2); this.getSpellAbility().getModes().setMaxModes(2); - + // Return target creature card from your graveyard to your hand; this.getSpellAbility().getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().getTargets().add(new TargetCardInYourGraveyard(1, new FilterCreatureCard("creature card from your graveyard"))); - - // or Target player discards a card; + this.getSpellAbility().getTargets().add(new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // or Target player discards a card; Mode mode = new Mode(); mode.getEffects().add(new DiscardTargetEffect(1)); mode.getTargets().add(new TargetPlayer()); - this.getSpellAbility().getModes().addMode(mode); - + this.getSpellAbility().getModes().addMode(mode); + // or Destroy target artifact; mode = new Mode(); mode.getEffects().add(new DestroyTargetEffect()); mode.getTargets().add(new TargetPermanent(filter)); - this.getSpellAbility().getModes().addMode(mode); - + this.getSpellAbility().getModes().addMode(mode); + // or Kolaghan's Command deals 2 damage to target creature or player. mode = new Mode(); mode.getEffects().add(new DamageTargetEffect(2)); mode.getTargets().add(new TargetCreatureOrPlayer()); - this.getSpellAbility().getModes().addMode(mode); + this.getSpellAbility().getModes().addMode(mode); } public KolaghansCommand(final KolaghansCommand card) { diff --git a/Mage.Sets/src/mage/cards/l/LifeDeath.java b/Mage.Sets/src/mage/cards/l/LifeDeath.java index 8506ce86324..e1e074316aa 100644 --- a/Mage.Sets/src/mage/cards/l/LifeDeath.java +++ b/Mage.Sets/src/mage/cards/l/LifeDeath.java @@ -40,8 +40,8 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.token.Token; import mage.players.Player; @@ -64,7 +64,7 @@ public class LifeDeath extends SplitCard { // Death // Return target creature card from your graveyard to the battlefield. You lose life equal to its converted mana cost. - Target target = new TargetCardInYourGraveyard(1, new FilterCreatureCard("creature card from your graveyard")); + Target target = new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); getRightHalfCard().getSpellAbility().addTarget(target); getRightHalfCard().getSpellAbility().addEffect(new DeathEffect()); diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java index 7e3ee59e207..8251450c58e 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java @@ -40,7 +40,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -75,7 +75,7 @@ public class LilianaDeathsMajesty extends CardImpl { // -3: Return target creature card from your graveyard to the battlefield. That creature is a black Zombie in addition to its other colors and types. ability = new LoyaltyAbility(new BecomesBlackZombieAdditionEffect() // because the effect has to be active for triggered effects that e.g. check if the creature entering is a Zombie, the continuous effect needs to be added before the card moving effect is applied .setText(""), -3); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect() .setText("Return target creature card from your graveyard to the battlefield. That creature is a black Zombie in addition to its other colors and types")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java b/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java index 47174d5a4ca..e0f786e2fd5 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java +++ b/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java @@ -40,12 +40,12 @@ import mage.cards.Card; 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.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.command.emblems.LilianaTheLastHopeEmblem; import mage.players.Player; @@ -114,7 +114,7 @@ class LilianaTheLastHopeEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) diff --git a/Mage.Sets/src/mage/cards/m/MakeshiftMannequin.java b/Mage.Sets/src/mage/cards/m/MakeshiftMannequin.java index 4fb9835ab51..0854b7f7943 100644 --- a/Mage.Sets/src/mage/cards/m/MakeshiftMannequin.java +++ b/Mage.Sets/src/mage/cards/m/MakeshiftMannequin.java @@ -45,7 +45,7 @@ import mage.constants.SubLayer; import mage.constants.Zone; import mage.counters.CounterType; import mage.counters.Counters; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -59,11 +59,11 @@ import mage.target.targetpointer.FixedTarget; public class MakeshiftMannequin extends CardImpl { public MakeshiftMannequin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); // Return target creature card from your graveyard to the battlefield with a mannequin counter on it. For as long as that creature has a mannequin counter on it, it has "When this creature becomes the target of a spell or ability, sacrifice it." this.getSpellAbility().addEffect(new MakeshiftMannequinEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public MakeshiftMannequin(final MakeshiftMannequin card) { diff --git a/Mage.Sets/src/mage/cards/m/MakeshiftMauler.java b/Mage.Sets/src/mage/cards/m/MakeshiftMauler.java index 505d82b3ae7..02fe0401345 100644 --- a/Mage.Sets/src/mage/cards/m/MakeshiftMauler.java +++ b/Mage.Sets/src/mage/cards/m/MakeshiftMauler.java @@ -34,7 +34,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -44,7 +44,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class MakeshiftMauler extends CardImpl { public MakeshiftMauler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HORROR); @@ -52,7 +52,7 @@ public class MakeshiftMauler extends CardImpl { this.toughness = new MageInt(5); // As an additional cost to cast Makeshift Mauler, exile a creature card from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); } public MakeshiftMauler(final MakeshiftMauler card) { diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java index cd3f5d8513d..7074ea10795 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java @@ -35,7 +35,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInYourGraveyard; @@ -57,7 +57,7 @@ public class MarchOfTheDrowned extends CardImpl { // Choose one — // &bull; Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // &bull; Return two target Pirate cards from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/m/MidnightRecovery.java b/Mage.Sets/src/mage/cards/m/MidnightRecovery.java index fade3a6e53d..11ef4fba31a 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightRecovery.java +++ b/Mage.Sets/src/mage/cards/m/MidnightRecovery.java @@ -33,7 +33,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,13 +42,12 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class MidnightRecovery extends CardImpl { - public MidnightRecovery (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); - + public MidnightRecovery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Cipher (Then you may exilce this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of the encoded card without paying its mana cost.) this.getSpellAbility().addEffect(new CipherEffect()); @@ -60,7 +59,7 @@ public class MidnightRecovery extends CardImpl { } @Override - public MidnightRecovery copy() { + public MidnightRecovery copy() { return new MidnightRecovery(this); } } diff --git a/Mage.Sets/src/mage/cards/m/MidnightRitual.java b/Mage.Sets/src/mage/cards/m/MidnightRitual.java index 718e51ad01a..042dc6a37d9 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightRitual.java +++ b/Mage.Sets/src/mage/cards/m/MidnightRitual.java @@ -38,7 +38,7 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.ZombieToken; import mage.players.Player; @@ -50,14 +50,12 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class MidnightRitual extends CardImpl { - private final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public MidnightRitual(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{2}{B}"); // Exile X target creature cards from your graveyard. // For each creature card exiled this way, create a 2/2 black Zombie creature token. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new MidnightRitualEffect()); } @@ -65,7 +63,7 @@ public class MidnightRitual extends CardImpl { public void adjustTargets(Ability ability, Game game) { if (ability instanceof SpellAbility) { ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), filter)); + ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } } diff --git a/Mage.Sets/src/mage/cards/m/MorgueBurst.java b/Mage.Sets/src/mage/cards/m/MorgueBurst.java index 1b7f7385528..9e2e7b20daf 100644 --- a/Mage.Sets/src/mage/cards/m/MorgueBurst.java +++ b/Mage.Sets/src/mage/cards/m/MorgueBurst.java @@ -37,7 +37,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -51,11 +51,11 @@ import mage.target.common.TargetCreatureOrPlayer; public class MorgueBurst extends CardImpl { public MorgueBurst(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{R}"); // Return target creature card from your graveyard to your hand. Morgue Burst deals damage to target creature or player equal to the power of the card returned this way. this.getSpellAbility().addEffect(new MorgueBurstEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addTarget(new TargetCreatureOrPlayer()); } diff --git a/Mage.Sets/src/mage/cards/m/MortuaryMire.java b/Mage.Sets/src/mage/cards/m/MortuaryMire.java index 885f9351d9a..895d8f4d4ee 100644 --- a/Mage.Sets/src/mage/cards/m/MortuaryMire.java +++ b/Mage.Sets/src/mage/cards/m/MortuaryMire.java @@ -36,7 +36,7 @@ import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -46,14 +46,14 @@ import mage.target.common.TargetCardInYourGraveyard; public class MortuaryMire extends CardImpl { public MortuaryMire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Mortuary Mire enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // When Mortuary Mire enters the battlefield, you may put target creature card from your graveyard on top of your library. Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // {T}: Add {B} to your mana pool. diff --git a/Mage.Sets/src/mage/cards/n/NecromanticThirst.java b/Mage.Sets/src/mage/cards/n/NecromanticThirst.java index 8f92ea3273b..49a6941e0fe 100644 --- a/Mage.Sets/src/mage/cards/n/NecromanticThirst.java +++ b/Mage.Sets/src/mage/cards/n/NecromanticThirst.java @@ -36,10 +36,10 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -51,7 +51,7 @@ import mage.target.common.TargetCreaturePermanent; public class NecromanticThirst extends CardImpl { public NecromanticThirst(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -59,13 +59,13 @@ public class NecromanticThirst extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // Whenever enchanted creature deals combat damage to a player, you may return target creature card from your graveyard to your hand. Ability ability = new DealsDamageToAPlayerAttachedTriggeredAbility( - new ReturnFromGraveyardToHandTargetEffect(), + new ReturnFromGraveyardToHandTargetEffect(), "enchanted creature", true, false, true, TargetController.ANY); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); - this.addAbility(ability); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); } public NecromanticThirst(final NecromanticThirst card) { diff --git a/Mage.Sets/src/mage/cards/n/NullCaller.java b/Mage.Sets/src/mage/cards/n/NullCaller.java index 4aa4992f634..8cd0d456db8 100644 --- a/Mage.Sets/src/mage/cards/n/NullCaller.java +++ b/Mage.Sets/src/mage/cards/n/NullCaller.java @@ -39,7 +39,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.permanent.token.ZombieToken; import mage.target.common.TargetCardInYourGraveyard; @@ -50,7 +50,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class NullCaller extends CardImpl { public NullCaller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(2); @@ -60,7 +60,7 @@ public class NullCaller extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken(), 1, true, false), new ManaCostsImpl<>("{3}{B}")); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OversoldCemetery.java b/Mage.Sets/src/mage/cards/o/OversoldCemetery.java index e3d85c4dfa6..8a059f26f7b 100644 --- a/Mage.Sets/src/mage/cards/o/OversoldCemetery.java +++ b/Mage.Sets/src/mage/cards/o/OversoldCemetery.java @@ -38,6 +38,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInGraveyard; @@ -48,12 +49,12 @@ import mage.target.common.TargetCardInGraveyard; public class OversoldCemetery extends CardImpl { public OversoldCemetery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // At the beginning of your upkeep, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), TargetController.YOU, true); + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), TargetController.YOU, true); ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard())); - CardsInControllerGraveCondition condition = new CardsInControllerGraveCondition(4, new FilterCreatureCard("creature card from your graveyard")); + CardsInControllerGraveCondition condition = new CardsInControllerGraveCondition(4, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); this.addAbility(new ConditionalTriggeredAbility(ability, condition, "At the beginning of your upkeep, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand.")); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java b/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java index 28738beb3e7..44eb2359ca6 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java @@ -36,10 +36,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.Target; @@ -52,7 +52,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class PhyrexianDelver extends CardImpl { public PhyrexianDelver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); @@ -60,7 +60,7 @@ public class PhyrexianDelver extends CardImpl { // When Phyrexian Delver enters the battlefield, return target creature card from your graveyard to the battlefield. You lose life equal to that card's converted mana cost. Ability ability = new EntersBattlefieldTriggeredAbility(new PhyrexianDelverEffect(), false); - Target target = new TargetCardInYourGraveyard(1, new FilterCreatureCard("creature card from your graveyard")); + Target target = new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java b/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java index dafa145b943..f5d311a8470 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,13 +47,12 @@ import mage.target.common.TargetCardInYourGraveyard; public class PhyrexianReclamation extends CardImpl { public PhyrexianReclamation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // {1}{B}, Pay 2 life: Return target creature card from your graveyard to your hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{1}{B}")); ability.addCost(new PayLifeCost(2)); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PitKeeper.java b/Mage.Sets/src/mage/cards/p/PitKeeper.java index 0ee13d589d5..c898984bbed 100644 --- a/Mage.Sets/src/mage/cards/p/PitKeeper.java +++ b/Mage.Sets/src/mage/cards/p/PitKeeper.java @@ -39,6 +39,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; @@ -51,7 +52,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class PitKeeper extends CardImpl { public PitKeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); @@ -59,7 +60,7 @@ public class PitKeeper extends CardImpl { // When Pit Keeper enters the battlefield, if you have four or more creature cards in your graveyard, you may return target creature card from your graveyard to your hand. TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - triggeredAbility.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + triggeredAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(new ConditionalTriggeredAbility( triggeredAbility, new CreatureCardsInControllerGraveCondition(4), @@ -77,6 +78,7 @@ public class PitKeeper extends CardImpl { } class CreatureCardsInControllerGraveCondition implements Condition { + private int value; public CreatureCardsInControllerGraveCondition(int value) { @@ -86,10 +88,9 @@ class CreatureCardsInControllerGraveCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Player p = game.getPlayer(source.getControllerId()); - if (p != null && p.getGraveyard().count(new FilterCreatureCard(), game) >= value) - { - return true; + if (p != null && p.getGraveyard().count(new FilterCreatureCard(), game) >= value) { + return true; } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/PostmortemLunge.java b/Mage.Sets/src/mage/cards/p/PostmortemLunge.java index f636721db0f..0aaa7aca999 100644 --- a/Mage.Sets/src/mage/cards/p/PostmortemLunge.java +++ b/Mage.Sets/src/mage/cards/p/PostmortemLunge.java @@ -40,6 +40,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; @@ -58,7 +59,7 @@ public class PostmortemLunge extends CardImpl { // Return target creature card with converted mana cost X from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. this.getSpellAbility().addEffect(new PostmortemLungeEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public PostmortemLunge(final PostmortemLunge card) { diff --git a/Mage.Sets/src/mage/cards/p/PulsemageAdvocate.java b/Mage.Sets/src/mage/cards/p/PulsemageAdvocate.java index 2352409ffeb..63f97e01710 100644 --- a/Mage.Sets/src/mage/cards/p/PulsemageAdvocate.java +++ b/Mage.Sets/src/mage/cards/p/PulsemageAdvocate.java @@ -39,12 +39,12 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.other.OwnerPredicate; import mage.game.Game; import mage.players.Player; @@ -58,12 +58,13 @@ import mage.target.common.TargetCardInYourGraveyard; public class PulsemageAdvocate extends CardImpl { private static final FilterCard filter = new FilterCard("cards from an opponent's graveyard"); + static { filter.add(new OwnerPredicate(TargetController.NOT_YOU)); } public PulsemageAdvocate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); @@ -72,7 +73,7 @@ public class PulsemageAdvocate extends CardImpl { // {tap}: Return three target cards from an opponent's graveyard to his or her hand. Return target creature card from your graveyard to the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PulsemageAdvocateEffect(), new TapSourceCost()); ability.addTarget(new TargetCardInASingleGraveyard(3, 3, filter)); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RaiseDead.java b/Mage.Sets/src/mage/cards/r/RaiseDead.java index 6b4a873533e..c21e5a54eac 100644 --- a/Mage.Sets/src/mage/cards/r/RaiseDead.java +++ b/Mage.Sets/src/mage/cards/r/RaiseDead.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -41,15 +41,11 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class RaiseDead extends CardImpl { - - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public RaiseDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Return target creature card from your graveyard to your hand. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/r/RavosSoultender.java b/Mage.Sets/src/mage/cards/r/RavosSoultender.java index 890ec3103b9..4413adcb3da 100644 --- a/Mage.Sets/src/mage/cards/r/RavosSoultender.java +++ b/Mage.Sets/src/mage/cards/r/RavosSoultender.java @@ -39,7 +39,7 @@ import mage.abilities.keyword.PartnerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -51,7 +51,7 @@ public class RavosSoultender extends CardImpl { public RavosSoultender(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{B}"); - addSuperType(SuperType.LEGENDARY); + addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); @@ -65,7 +65,7 @@ public class RavosSoultender extends CardImpl { // At the beginning of your upkeep, you may return target creature card from your graveyard to your hand. Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), TargetController.YOU, true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // Partner diff --git a/Mage.Sets/src/mage/cards/r/ReapingTheGraves.java b/Mage.Sets/src/mage/cards/r/ReapingTheGraves.java index 070b57e6864..2b9e1c9c08c 100644 --- a/Mage.Sets/src/mage/cards/r/ReapingTheGraves.java +++ b/Mage.Sets/src/mage/cards/r/ReapingTheGraves.java @@ -33,7 +33,7 @@ import mage.abilities.keyword.StormAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -45,8 +45,8 @@ public class ReapingTheGraves extends CardImpl { public ReapingTheGraves(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); - // Return target creature card from your graveyard to your hand. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + // Return target creature card from your graveyard to your hand. + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return target creature card from your graveyard to your hand.")); // Storm this.addAbility(new StormAbility()); diff --git a/Mage.Sets/src/mage/cards/r/Recover.java b/Mage.Sets/src/mage/cards/r/Recover.java index 1b97209356b..52f32994003 100644 --- a/Mage.Sets/src/mage/cards/r/Recover.java +++ b/Mage.Sets/src/mage/cards/r/Recover.java @@ -33,7 +33,7 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,14 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class Recover extends CardImpl { - private static FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public Recover(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Return target creature card from your graveyard to your hand. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/cards/r/RelentlessSkaabs.java b/Mage.Sets/src/mage/cards/r/RelentlessSkaabs.java index 56ae0187345..5ac141a31eb 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessSkaabs.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessSkaabs.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -45,14 +45,14 @@ import mage.target.common.TargetCardInYourGraveyard; public class RelentlessSkaabs extends CardImpl { public RelentlessSkaabs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(4); this.toughness = new MageInt(4); // As an additional cost to cast Relentless Skaabs, exile a creature card from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); // Undying this.addAbility(new UndyingAbility()); } diff --git a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java index c41226a3b73..4d32468f9eb 100644 --- a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java +++ b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java @@ -27,22 +27,14 @@ */ package mage.cards.r; -import java.util.List; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; -import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; /** @@ -51,26 +43,25 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class RememberTheFallen extends CardImpl { - private static final FilterCreatureCard filterCreature = new FilterCreatureCard("creature card from your graveyard"); private static final FilterArtifactCard filterArtifact = new FilterArtifactCard("artifact card from your graveyard"); public RememberTheFallen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + // Choose one or both — + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + // • Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCreature)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + // • Return target artifact card from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnToHandTargetEffect()); mode.getTargets().add(new TargetCardInYourGraveyard(filterArtifact)); this.getSpellAbility().addMode(mode); - mode = new Mode(); - mode.getTargets().add(new TargetCardInYourGraveyard(filterCreature)); - mode.getTargets().add(new TargetCardInYourGraveyard(filterArtifact)); - mode.getEffects().add(new RememberTheFallenEffect()); - this.getSpellAbility().addMode(mode); } public RememberTheFallen(final RememberTheFallen card) { @@ -82,34 +73,3 @@ public class RememberTheFallen extends CardImpl { return new RememberTheFallen(this); } } - -class RememberTheFallenEffect extends OneShotEffect { - - public RememberTheFallenEffect() { - super(Outcome.ReturnToHand); - this.staticText = "Return target creature card and target artifact card from your graveyard to your hand"; - } - - public RememberTheFallenEffect(final RememberTheFallenEffect effect) { - super(effect); - } - - @Override - public RememberTheFallenEffect copy() { - return new RememberTheFallenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (Target target : source.getTargets()) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card card = game.getCard(targetId); - if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, true); - } - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/Repurpose.java b/Mage.Sets/src/mage/cards/r/Repurpose.java index 080ebd5d9ee..e01cc8ee09f 100644 --- a/Mage.Sets/src/mage/cards/r/Repurpose.java +++ b/Mage.Sets/src/mage/cards/r/Repurpose.java @@ -34,7 +34,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; @@ -46,7 +46,7 @@ import mage.target.targetpointer.SecondTargetPointer; public class Repurpose extends CardImpl { public Repurpose(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // Destroy target creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); @@ -57,7 +57,7 @@ public class Repurpose extends CardImpl { effect.setTargetPointer(SecondTargetPointer.getInstance()); effect.setText("Return up to one target creature card from graveyard to your hand."); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public Repurpose(final Repurpose card) { diff --git a/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java b/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java index cc0434d1d96..4d9e916f802 100644 --- a/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java +++ b/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java @@ -27,6 +27,7 @@ */ package mage.cards.r; +import java.util.UUID; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -34,12 +35,10 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * * @author LevelX2 @@ -50,7 +49,7 @@ public class ResourcefulReturn extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Return target creature card from your graveyard to your hand. If you control an artifact, draw a card. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new PermanentsOnTheBattlefieldCondition(new FilterControlledArtifactPermanent()), diff --git a/Mage.Sets/src/mage/cards/r/RestlessDreams.java b/Mage.Sets/src/mage/cards/r/RestlessDreams.java index 804fbc88121..b1fb4477d45 100644 --- a/Mage.Sets/src/mage/cards/r/RestlessDreams.java +++ b/Mage.Sets/src/mage/cards/r/RestlessDreams.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class RestlessDreams extends CardImpl { public RestlessDreams(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // As an additional cost to cast Restless Dreams, discard X cards. this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); @@ -62,14 +62,14 @@ public class RestlessDreams extends CardImpl { public RestlessDreams(final RestlessDreams card) { super(card); } - + @Override public void adjustTargets(Ability ability, Game game) { int xValue = new GetXValue().calculate(game, ability, null); - Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard("creature card from your graveyard")); - ability.addTarget(target); + Target target = new TargetCardInYourGraveyard(xValue, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + ability.addTarget(target); } - + @Override public RestlessDreams copy() { return new RestlessDreams(this); diff --git a/Mage.Sets/src/mage/cards/r/Resurrection.java b/Mage.Sets/src/mage/cards/r/Resurrection.java index 34d1be82240..c84f21fa990 100644 --- a/Mage.Sets/src/mage/cards/r/Resurrection.java +++ b/Mage.Sets/src/mage/cards/r/Resurrection.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,12 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class Resurrection extends CardImpl { public Resurrection(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } diff --git a/Mage.Sets/src/mage/cards/r/ReturnToBattle.java b/Mage.Sets/src/mage/cards/r/ReturnToBattle.java index 9c1f370114f..bbaaa9d0d84 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnToBattle.java +++ b/Mage.Sets/src/mage/cards/r/ReturnToBattle.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,11 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class ReturnToBattle extends CardImpl { public ReturnToBattle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public ReturnToBattle(final ReturnToBattle card) { diff --git a/Mage.Sets/src/mage/cards/r/RevivingMelody.java b/Mage.Sets/src/mage/cards/r/RevivingMelody.java index e0e1effce2c..69327c6dd0f 100644 --- a/Mage.Sets/src/mage/cards/r/RevivingMelody.java +++ b/Mage.Sets/src/mage/cards/r/RevivingMelody.java @@ -34,7 +34,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetCardInYourGraveyard; @@ -51,16 +51,15 @@ public class RevivingMelody extends CardImpl { } public RevivingMelody(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); - - // Choose one or both - + // Choose one or both - this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - + //Return target creature card from your graveyard to your hand; this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // and/or return target enchantment card from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/r/ReyaDawnbringer.java b/Mage.Sets/src/mage/cards/r/ReyaDawnbringer.java index 55826ca3cdd..fe20bf2d3f8 100644 --- a/Mage.Sets/src/mage/cards/r/ReyaDawnbringer.java +++ b/Mage.Sets/src/mage/cards/r/ReyaDawnbringer.java @@ -39,7 +39,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class ReyaDawnbringer extends CardImpl { public ReyaDawnbringer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{W}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{W}{W}{W}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ANGEL); @@ -57,7 +57,7 @@ public class ReyaDawnbringer extends CardImpl { this.toughness = new MageInt(6); this.addAbility(FlyingAbility.getInstance()); Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), TargetController.YOU, true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java b/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java index 867c78a2813..bd26e5c8b5c 100644 --- a/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java +++ b/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java @@ -41,7 +41,6 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; /** @@ -63,7 +62,7 @@ public class SheoldredWhisperingOne extends CardImpl { // At the beginning of your upkeep, return target creature card from your graveyard to the battlefield. Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(false), TargetController.YOU, false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // At the beginning of each opponent's upkeep, that player sacrifices a creature. diff --git a/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java b/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java index e9f1681d120..660a16c9edc 100644 --- a/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java +++ b/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,7 +47,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class SibsigMuckdraggers extends CardImpl { public SibsigMuckdraggers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{8}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{8}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(6); @@ -56,7 +56,7 @@ public class SibsigMuckdraggers extends CardImpl { this.addAbility(new DelveAbility()); // When Sibsig Muckdraggers enters the battlefield, return target creature card from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkaabGoliath.java b/Mage.Sets/src/mage/cards/s/SkaabGoliath.java index 9102a474a7a..216e7b3ca6b 100644 --- a/Mage.Sets/src/mage/cards/s/SkaabGoliath.java +++ b/Mage.Sets/src/mage/cards/s/SkaabGoliath.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -45,7 +45,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class SkaabGoliath extends CardImpl { public SkaabGoliath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.GIANT); @@ -53,7 +53,7 @@ public class SkaabGoliath extends CardImpl { this.toughness = new MageInt(9); // As an additional cost to cast Skaab Goliath, exile two creature cards from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, 2, new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, 2, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); this.addAbility(TrampleAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/s/SkaabRuinator.java b/Mage.Sets/src/mage/cards/s/SkaabRuinator.java index 2aeb83644e9..8dea4f89e35 100644 --- a/Mage.Sets/src/mage/cards/s/SkaabRuinator.java +++ b/Mage.Sets/src/mage/cards/s/SkaabRuinator.java @@ -39,11 +39,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AsThoughEffectType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; @@ -54,7 +54,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class SkaabRuinator extends CardImpl { public SkaabRuinator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HORROR); @@ -62,11 +62,11 @@ public class SkaabRuinator extends CardImpl { this.toughness = new MageInt(6); // As an additional cost to cast Skaab Ruinator, exile three creature cards from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3, new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); // Flying this.addAbility(FlyingAbility.getInstance()); - + // You may cast Skaab Ruinator from your graveyard. this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, new SkaabRuinatorPlayEffect())); } @@ -81,7 +81,6 @@ public class SkaabRuinator extends CardImpl { } } - class SkaabRuinatorPlayEffect extends AsThoughEffectImpl { public SkaabRuinatorPlayEffect() { @@ -105,8 +104,8 @@ class SkaabRuinatorPlayEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(source.getSourceId()) && - affectedControllerId.equals(source.getControllerId())) { + if (objectId.equals(source.getSourceId()) + && affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(source.getSourceId()); if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { return true; diff --git a/Mage.Sets/src/mage/cards/s/SoulExchange.java b/Mage.Sets/src/mage/cards/s/SoulExchange.java index 995a4241dd2..4b91d363ed5 100644 --- a/Mage.Sets/src/mage/cards/s/SoulExchange.java +++ b/Mage.Sets/src/mage/cards/s/SoulExchange.java @@ -27,6 +27,7 @@ */ package mage.cards.s; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.common.ExileTargetCost; @@ -38,14 +39,12 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; -import java.util.UUID; - /** * @author MarcoMarin */ @@ -58,7 +57,7 @@ public class SoulExchange extends CardImpl { Cost cost = new ExileTargetCost(new TargetControlledCreaturePermanent()); this.getSpellAbility().addCost(cost); // Return target creature card from your graveyard to the battlefield. Put a +2/+2 counter on that creature if the exiled creature was a Thrull. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new SoulExchangeEffect()); } @@ -92,10 +91,12 @@ class SoulExchangeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { ReturnFromGraveyardToBattlefieldTargetEffect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); - if (!effect.apply(game, source)) return false; + if (!effect.apply(game, source)) { + return false; + } for (Cost c : source.getCosts()) { - /* if (!c.getTargets().isEmpty()){ + /* if (!c.getTargets().isEmpty()){ UUID t = c.getTargets().getFirstTarget(); Permanent exiled = game.getPermanentOrLKIBattlefield(t);*/ if (c.isPaid() && c instanceof ExileTargetCost) { @@ -105,10 +106,12 @@ class SoulExchangeEffect extends OneShotEffect { game.getPermanent(source.getFirstTarget()).addCounters(CounterType.P2P2.createInstance(), source, game); return true; } - } else return false; + } else { + return false; + } } } } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SoulManipulation.java b/Mage.Sets/src/mage/cards/s/SoulManipulation.java index ae156d39e80..a351ce628d4 100644 --- a/Mage.Sets/src/mage/cards/s/SoulManipulation.java +++ b/Mage.Sets/src/mage/cards/s/SoulManipulation.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterSpell; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetSpell; import mage.target.common.TargetCardInYourGraveyard; @@ -45,34 +45,30 @@ import mage.target.common.TargetCardInYourGraveyard; * @author jeffwadsworth */ public class SoulManipulation extends CardImpl { - + private static final FilterSpell filter = new FilterSpell("creature spell"); - private static final FilterCreatureCard filter2 = new FilterCreatureCard("creature card from your graveyard"); - + static { filter.add(new CardTypePredicate(CardType.CREATURE)); } public SoulManipulation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{B}"); - - - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{B}"); // Choose one or both - this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - + // Counter target creature spell; this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(filter)); - + // and/or return target creature card from your graveyard to your hand. Mode mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(filter2)); + mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addMode(mode); - + } public SoulManipulation(final SoulManipulation card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulSeparator.java b/Mage.Sets/src/mage/cards/s/SoulSeparator.java index d0e4b229185..31ee19acfd0 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSeparator.java +++ b/Mage.Sets/src/mage/cards/s/SoulSeparator.java @@ -42,7 +42,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.ZombieToken2; import mage.players.Player; @@ -55,7 +55,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class SoulSeparator extends CardImpl { public SoulSeparator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {5}, {T}, Sacrifice Soul Separator: Exile target creature card from your graveyard. // Create a token that's a copy of that card except it's 1/1, it's a Spirit in addition to its other types, and it has flying. @@ -66,7 +66,7 @@ public class SoulSeparator extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, copyEffect, new ManaCostsImpl("{5}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addEffect(new SoulSeparatorEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SoullessRevival.java b/Mage.Sets/src/mage/cards/s/SoullessRevival.java index 692f8c20e69..e3608cade4e 100644 --- a/Mage.Sets/src/mage/cards/s/SoullessRevival.java +++ b/Mage.Sets/src/mage/cards/s/SoullessRevival.java @@ -27,17 +27,16 @@ */ package mage.cards.s; +import java.util.UUID; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.SpliceOntoArcaneAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * * @author LevelX2 @@ -45,13 +44,12 @@ import java.util.UUID; public class SoullessRevival extends CardImpl { public SoullessRevival(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); this.subtype.add(SubType.ARCANE); - // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Splice onto Arcane {1}{B} this.addAbility(new SpliceOntoArcaneAbility("{1}{B}")); } diff --git a/Mage.Sets/src/mage/cards/s/StitchTogether.java b/Mage.Sets/src/mage/cards/s/StitchTogether.java index 7aa4224708e..7b3928ed782 100644 --- a/Mage.Sets/src/mage/cards/s/StitchTogether.java +++ b/Mage.Sets/src/mage/cards/s/StitchTogether.java @@ -36,7 +36,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -46,7 +46,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class StitchTogether extends CardImpl { public StitchTogether(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}"); // Return target creature card from your graveyard to your hand. // Threshold - Return that card from your graveyard to the battlefield instead if seven or more cards are in your graveyard. @@ -56,7 +56,7 @@ public class StitchTogether extends CardImpl { new CardsInControllerGraveCondition(7), "Return target creature card from your graveyard to your hand.

Threshold - Return that card from your graveyard to the battlefield instead if seven or more cards are in your graveyard."); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public StitchTogether(final StitchTogether card) { diff --git a/Mage.Sets/src/mage/cards/s/StitchedDrake.java b/Mage.Sets/src/mage/cards/s/StitchedDrake.java index b23d24091f4..34d3aba131a 100644 --- a/Mage.Sets/src/mage/cards/s/StitchedDrake.java +++ b/Mage.Sets/src/mage/cards/s/StitchedDrake.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -44,7 +44,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class StitchedDrake extends CardImpl { public StitchedDrake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.DRAKE); @@ -54,7 +54,7 @@ public class StitchedDrake extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // As an additional cost to cast Stitched Drake, exile a creature card from your graveyard. - this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")))); + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); } public StitchedDrake(final StitchedDrake card) { diff --git a/Mage.Sets/src/mage/cards/s/StrandsOfNight.java b/Mage.Sets/src/mage/cards/s/StrandsOfNight.java index f737bb36512..ab46d2cb96d 100644 --- a/Mage.Sets/src/mage/cards/s/StrandsOfNight.java +++ b/Mage.Sets/src/mage/cards/s/StrandsOfNight.java @@ -39,8 +39,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; -import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledPermanent; @@ -56,16 +56,15 @@ public class StrandsOfNight extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SWAMP)); } - - public StrandsOfNight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + public StrandsOfNight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // {B}{B}, Pay 2 life, Sacrifice a Swamp: Return target creature card from your graveyard to the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{B}{B}")); ability.addCost(new PayLifeCost(2)); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SuddenReclamation.java b/Mage.Sets/src/mage/cards/s/SuddenReclamation.java index a90a13e09e7..2908156d3f2 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenReclamation.java +++ b/Mage.Sets/src/mage/cards/s/SuddenReclamation.java @@ -39,7 +39,7 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.players.Player; @@ -53,7 +53,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class SuddenReclamation extends CardImpl { public SuddenReclamation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); // Put the top four cards of your library into your graveyard, then return a creature card and a land card from your graveyard to your hand. this.getSpellAbility().addEffect(new PutTopCardOfLibraryIntoGraveControllerEffect(4)); @@ -91,7 +91,7 @@ class SuddenReclamationEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Cards cardsToHand = new CardsImpl(); - Target target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseTarget(outcome, target, source, game)) { diff --git a/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java b/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java index e96d1af110d..c510846726c 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java @@ -44,10 +44,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; @@ -70,7 +70,7 @@ public class SwordOfLightAndShadow extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ProtectionAbility.from(ObjectColor.WHITE, ObjectColor.BLACK), AttachmentType.EQUIPMENT))); // Whenever equipped creature deals combat damage to a player, you gain 3 life and you may return up to one target creature card from your graveyard to your hand. Ability ability = new SwordOfLightAndShadowAbility(); - ability.addTarget(new TargetCardInYourGraveyard(0, 1, new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); diff --git a/Mage.Sets/src/mage/cards/t/TorturedExistence.java b/Mage.Sets/src/mage/cards/t/TorturedExistence.java index 5ed089ee46b..14bd4652c45 100644 --- a/Mage.Sets/src/mage/cards/t/TorturedExistence.java +++ b/Mage.Sets/src/mage/cards/t/TorturedExistence.java @@ -37,6 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; @@ -47,13 +48,13 @@ import mage.target.common.TargetCardInYourGraveyard; public class TorturedExistence extends CardImpl { public TorturedExistence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // {B}, Discard a creature card: Return target creature card from your graveyard to your hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{B}")); ability.addCost(new DiscardCardCost(new FilterCreatureCard())); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); - this.addAbility(ability); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); } public TorturedExistence(final TorturedExistence card) { diff --git a/Mage.Sets/src/mage/cards/t/TriassicEgg.java b/Mage.Sets/src/mage/cards/t/TriassicEgg.java index 1457eee405e..a33791f3519 100644 --- a/Mage.Sets/src/mage/cards/t/TriassicEgg.java +++ b/Mage.Sets/src/mage/cards/t/TriassicEgg.java @@ -44,6 +44,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; @@ -55,29 +56,29 @@ import mage.target.common.TargetCardInYourGraveyard; public class TriassicEgg extends CardImpl { public TriassicEgg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {3}, {tap}: Put a hatchling counter on Triassic Egg. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.HATCHLING.createInstance(), true), + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.HATCHLING.createInstance(), true), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); this.addAbility(ability); - + // Sacrifice Triassic Egg: Choose one - You may put a creature card from your hand onto the battlefield; ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new PutPermanentOnBattlefieldEffect(new FilterCreatureCard("a creature card")), new SacrificeSourceCost(), new SourceHasCounterCondition(CounterType.HATCHLING, 2, Integer.MAX_VALUE), "Sacrifice Triassic Egg: Choose one - You may put a creature card from your hand onto the battlefield; or return target creature card from your graveyard to the battlefield. Activate this ability only if two or more hatchling counters are on {this}."); - + // or return target creature card from your graveyard to the battlefield. Activate this ability only if two or more hatchling counters are on Triassic Egg. Mode mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); - Target target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard")); + Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); mode.getTargets().add(target); ability.addMode(mode); - + this.addAbility(ability); } @@ -89,4 +90,4 @@ public class TriassicEgg extends CardImpl { public TriassicEgg copy() { return new TriassicEgg(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/u/UnburialRites.java b/Mage.Sets/src/mage/cards/u/UnburialRites.java index 02fcbd01602..9d214e9bc16 100644 --- a/Mage.Sets/src/mage/cards/u/UnburialRites.java +++ b/Mage.Sets/src/mage/cards/u/UnburialRites.java @@ -35,7 +35,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -44,12 +44,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class UnburialRites extends CardImpl { public UnburialRites(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Flashback {3}{W} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{3}{W}"), TimingRule.SORCERY)); diff --git a/Mage.Sets/src/mage/cards/u/Undertaker.java b/Mage.Sets/src/mage/cards/u/Undertaker.java index dd5b276a062..7988530cb7a 100644 --- a/Mage.Sets/src/mage/cards/u/Undertaker.java +++ b/Mage.Sets/src/mage/cards/u/Undertaker.java @@ -40,7 +40,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -49,10 +49,8 @@ import mage.target.common.TargetCardInYourGraveyard; */ public class Undertaker extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your graveyard"); - public Undertaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SPELLSHAPER); @@ -60,8 +58,8 @@ public class Undertaker extends CardImpl { this.toughness = new MageInt(1); // {B}, {tap}, Discard a card: Return target creature card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(),new ManaCostsImpl("{B}")); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{B}")); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WarrenPilferers.java b/Mage.Sets/src/mage/cards/w/WarrenPilferers.java index 3f5a5edd52a..d697e77fa12 100644 --- a/Mage.Sets/src/mage/cards/w/WarrenPilferers.java +++ b/Mage.Sets/src/mage/cards/w/WarrenPilferers.java @@ -38,7 +38,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; @@ -49,7 +49,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class WarrenPilferers extends CardImpl { public WarrenPilferers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.ROGUE); @@ -58,7 +58,7 @@ public class WarrenPilferers extends CardImpl { // When Warren Pilferers enters the battlefield, return target creature card from your graveyard to your hand. If that card is a Goblin card, Warren Pilferers gains haste until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new WarrenPilferersReturnEffect(), false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhipOfErebos.java b/Mage.Sets/src/mage/cards/w/WhipOfErebos.java index 0b396b39c9b..8f7562fd233 100644 --- a/Mage.Sets/src/mage/cards/w/WhipOfErebos.java +++ b/Mage.Sets/src/mage/cards/w/WhipOfErebos.java @@ -48,7 +48,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -64,7 +63,7 @@ import mage.target.targetpointer.FixedTarget; public class WhipOfErebos extends CardImpl { public WhipOfErebos(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.ARTIFACT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.ARTIFACT}, "{2}{B}{B}"); addSuperType(SuperType.LEGENDARY); // Creatures you control have lifelink. @@ -75,7 +74,7 @@ public class WhipOfErebos extends CardImpl { // Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new WhipOfErebosEffect(), new ManaCostsImpl("{2}{B}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addEffect(new WhipOfErebosReplacementEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java b/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java index f254e1ef1bc..4bea8efa4f0 100644 --- a/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java +++ b/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInGraveyard; /** @@ -42,12 +42,11 @@ import mage.target.common.TargetCardInGraveyard; public class WildwoodRebirth extends CardImpl { public WildwoodRebirth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public WildwoodRebirth(final WildwoodRebirth card) { diff --git a/Mage.Sets/src/mage/cards/w/Woebearer.java b/Mage.Sets/src/mage/cards/w/Woebearer.java index 36f290e9644..c0bd328e99f 100644 --- a/Mage.Sets/src/mage/cards/w/Woebearer.java +++ b/Mage.Sets/src/mage/cards/w/Woebearer.java @@ -37,7 +37,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -47,7 +47,7 @@ import mage.target.common.TargetCardInYourGraveyard; public class Woebearer extends CardImpl { public Woebearer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); this.toughness = new MageInt(3); @@ -56,7 +56,7 @@ public class Woebearer extends CardImpl { this.addAbility(FearAbility.getInstance()); // Whenever Woebearer deals combat damage to a player, you may return target creature card from your graveyard to your hand. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java index fd451034a07..9a759adf6f0 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java +++ b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java @@ -38,7 +38,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; @@ -50,30 +50,30 @@ import mage.target.common.TargetCreaturePermanent; public class WretchedConfluence extends CardImpl { public WretchedConfluence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}{B}"); - // Choose three. You may choose the same mode more than once. + // Choose three. You may choose the same mode more than once. this.getSpellAbility().getModes().setMinModes(3); this.getSpellAbility().getModes().setMaxModes(3); this.getSpellAbility().getModes().setEachModeMoreThanOnce(true); - - // - Target player draws a card and loses 1 life; + + // - Target player draws a card and loses 1 life; Effect effect = new LoseLifeTargetEffect(1); effect.setText("and loses 1 life"); this.getSpellAbility().addEffect(new DrawCardTargetEffect(1)); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPlayer()); - - // Target creature gets -2/-2 until end of turn; + + // Target creature gets -2/-2 until end of turn; Mode mode = new Mode(); mode.getEffects().add(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); mode.getTargets().add(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); - + // Return target creature card from your graveyard to your hand. mode = new Mode(); mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/z/Zombify.java b/Mage.Sets/src/mage/cards/z/Zombify.java index 0e6e972bdaa..866298a9bed 100644 --- a/Mage.Sets/src/mage/cards/z/Zombify.java +++ b/Mage.Sets/src/mage/cards/z/Zombify.java @@ -32,7 +32,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; /** @@ -42,12 +42,11 @@ import mage.target.common.TargetCardInYourGraveyard; public class Zombify extends CardImpl { public Zombify(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Return target creature card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); - + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } public Zombify(final Zombify card) { diff --git a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java index 7037434d077..1e10a0c0236 100644 --- a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java @@ -89,6 +89,9 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null) { card = card.getSecondCardFace(); + if (!card.isEnchantment() || !card.hasSubtype(SubType.AURA, game)) { + return false; + } } // Aura cards that go to battlefield face down (Manifest) don't have to select targets @@ -210,9 +213,9 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { if (card != null && (card.isEnchantment() && card.hasSubtype(SubType.AURA, game) || // in case of transformable enchantments (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null - && card.getSecondCardFace() != null - && card.getSecondCardFace().isEnchantment() - && card.getSecondCardFace().hasSubtype(SubType.AURA, game)))) { + && card.getSecondCardFace() != null + && card.getSecondCardFace().isEnchantment() + && card.getSecondCardFace().hasSubtype(SubType.AURA, game)))) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java index 0972efdf90a..b9276d882b2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlAttachedEffect.java @@ -43,8 +43,17 @@ import mage.players.Player; public class ReturnToBattlefieldUnderYourControlAttachedEffect extends OneShotEffect { public ReturnToBattlefieldUnderYourControlAttachedEffect() { + this("that card"); + } + + /** + * + * @param objectText text for the object to return (default: "that card") if + * you use constructor without this param + */ + public ReturnToBattlefieldUnderYourControlAttachedEffect(String objectText) { super(Outcome.Benefit); - staticText = "return that card to the battlefield under your control"; + staticText = "return " + objectText + " to the battlefield under your control"; } public ReturnToBattlefieldUnderYourControlAttachedEffect(final ReturnToBattlefieldUnderYourControlAttachedEffect effect) { diff --git a/Mage/src/main/java/mage/constants/Zone.java b/Mage/src/main/java/mage/constants/Zone.java index 09b24ea52c5..3c76fcf321f 100644 --- a/Mage/src/main/java/mage/constants/Zone.java +++ b/Mage/src/main/java/mage/constants/Zone.java @@ -43,9 +43,9 @@ public enum Zone { OUTSIDE(false), COMMAND(true); - private boolean isPublic; + private final boolean isPublic; - Zone(boolean isPublic){ + Zone(boolean isPublic) { this.isPublic = isPublic; } @@ -61,7 +61,7 @@ public enum Zone { return super.toString(); } - public boolean isPublicZone(){ + public boolean isPublicZone() { return isPublic; } } diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 66006123414..7ed7c5299f5 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -30,9 +30,10 @@ public final class StaticFilters { public static final FilterEnchantmentPermanent FILTER_ENCHANTMENT_PERMANENT = new FilterEnchantmentPermanent(); public static final FilterArtifactCard FILTER_CARD_ARTIFACT = new FilterArtifactCard(); + public static final FilterCard FILTER_CARD_ARTIFACT_OR_CREATURE = new FilterCard("artifact or creature card"); + public static final FilterCreatureCard FILTER_CARD_CREATURE_YOUR_GRAVEYARD = new FilterCreatureCard("creature card from your graveyard"); public static final FilterNonlandCard FILTER_CARD_NON_LAND = new FilterNonlandCard(); public static final FilterNonlandCard FILTER_CARD_A_NON_LAND = new FilterNonlandCard("a nonland card"); - public static final FilterCard FILTER_CARD_ARTIFACT_OR_CREATURE = new FilterCard("artifact or creature card"); public static final FilterPermanent FILTER_PERMANENT = new FilterPermanent(); public static final FilterCreaturePermanent FILTER_ARTIFACT_CREATURE_PERMANENT = new FilterArtifactCreaturePermanent(); @@ -60,6 +61,7 @@ public final class StaticFilters { public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE = new FilterCreaturePermanent(); public static final FilterCreaturePermanent FILTER_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature"); + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_CONTROLLED = new FilterCreaturePermanent("creature you control"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES = new FilterCreaturePermanent("creatures"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES_CONTROLLED = new FilterCreaturePermanent("creatures you control"); public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_GOBLINS = new FilterCreaturePermanent(SubType.GOBLIN, "Goblin creatures"); @@ -109,6 +111,7 @@ public final class StaticFilters { FILTER_ATTACKING_CREATURES.add(new AttackingPredicate()); + FILTER_PERMANENT_CREATURE_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); FILTER_PERMANENT_CREATURES_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); FILTER_PERMANENT_ARTIFACT_OR_CREATURE.add(Predicates.or( From 2672bd36d564968b47c4fe03fb091f25ddb5e010 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 11:40:44 +0100 Subject: [PATCH 46/54] [Rix] Added Jouney to Eternity and Jadelight Ranger. --- .../dl/sources/MythicspoilerComSource.java | 1 + .../src/mage/cards/a/AtzalCaveOfEternity.java | 83 +++++++++ .../src/mage/cards/j/JadelightRanger.java | 68 +++++++ .../src/mage/cards/j/JourneyToEternity.java | 123 +++++++++++++ Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 169 +++++++++--------- 5 files changed, 361 insertions(+), 83 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java create mode 100644 Mage.Sets/src/mage/cards/j/JadelightRanger.java create mode 100644 Mage.Sets/src/mage/cards/j/JourneyToEternity.java 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 7642f87d96b..a5f9412ceae 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 @@ -300,6 +300,7 @@ public enum MythicspoilerComSource implements CardImageSource { HashMap linksRix = new HashMap<>(); linksRix.put("vaultofcatlacan", "vaultofcatlacan"); + linksRix.put("atzalcaveofeternity", "atzalcaveofeternity"); manualLinks.put("RIX", linksRix); cardNameAliasesStart = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java b/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java new file mode 100644 index 00000000000..0546ce360f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java @@ -0,0 +1,83 @@ +/* + * 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.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author LevelX2 + */ +public class AtzalCaveOfEternity extends CardImpl { + + public AtzalCaveOfEternity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.addSuperType(SuperType.LEGENDARY); + + this.nightCard = true; + + // (Transforms from Journey to Eternity.) + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new InfoEffect("(Transforms from Journey to Eternity.)")); + ability.setRuleAtTheTop(true); + this.addAbility(ability); + + // {t}: Add one mana of any color to your mana pool. + this.addAbility(new AnyColorManaAbility()); + + // {3}{B}{G}, {T}: Return target creature card from your graveyard to the battlefield. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{3}{B}{G}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + public AtzalCaveOfEternity(final AtzalCaveOfEternity card) { + super(card); + } + + @Override + public AtzalCaveOfEternity copy() { + return new AtzalCaveOfEternity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JadelightRanger.java b/Mage.Sets/src/mage/cards/j/JadelightRanger.java new file mode 100644 index 00000000000..07e4227f1bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JadelightRanger.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.j; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ExploreSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author LevelX2 + */ +public class JadelightRanger extends CardImpl { + + public JadelightRanger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Jadelight Ranger enters the battlefield, it explores, then it explores again. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExploreSourceEffect().setText("it explores"), false); + ability.addEffect(new ExploreSourceEffect().setText(", then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process.) ")); + this.addAbility(ability); + } + + public JadelightRanger(final JadelightRanger card) { + super(card); + } + + @Override + public JadelightRanger copy() { + return new JadelightRanger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JourneyToEternity.java b/Mage.Sets/src/mage/cards/j/JourneyToEternity.java new file mode 100644 index 00000000000..5e34f1ebace --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JourneyToEternity.java @@ -0,0 +1,123 @@ +/* + * 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.j; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.TransformAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.a.AtzalCaveOfEternity; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author LevelX2 + */ +public class JourneyToEternity extends CardImpl { + + public JourneyToEternity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.AURA); + + this.transformable = true; + this.secondSideCardClazz = AtzalCaveOfEternity.class; + + // Enchant creature you control + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + ability = new DiesAttachedTriggeredAbility(new ReturnToBattlefieldUnderYourControlAttachedEffect("it"), "enchanted creature"); + ability.addEffect(new JourneyToEternityReturnTransformedSourceEffect()); + this.addAbility(ability); + + } + + public JourneyToEternity(final JourneyToEternity card) { + super(card); + } + + @Override + public JourneyToEternity copy() { + return new JourneyToEternity(this); + } +} + +class JourneyToEternityReturnTransformedSourceEffect extends OneShotEffect { + + public JourneyToEternityReturnTransformedSourceEffect() { + super(Outcome.Benefit); + this.staticText = ", then return {this} to the battlefield transformed under your control."; + } + + public JourneyToEternityReturnTransformedSourceEffect(final JourneyToEternityReturnTransformedSourceEffect effect) { + super(effect); + } + + @Override + public JourneyToEternityReturnTransformedSourceEffect copy() { + return new JourneyToEternityReturnTransformedSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (card != null && controller != null) { + Zone zone = game.getState().getZone(card.getId()); + // cards needs to be in public non battlefield zone + if (zone.equals(Zone.BATTLEFIELD) || !zone.isPublicZone()) { + return true; + } + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, false, null); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index dfdfabc45a4..aa575ac8533 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -1,83 +1,86 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author fireshoes - */ -public class RivalsOfIxalan extends ExpansionSet { - - private static final RivalsOfIxalan instance = new RivalsOfIxalan(); - - public static RivalsOfIxalan getInstance() { - return instance; - } - - private RivalsOfIxalan() { - super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); - this.blockName = "Ixalan"; - this.parentSet = Ixalan.getInstance(); - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - - cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); - cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); - cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); - cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); - cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); - cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); - cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); - cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); - cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); - cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); - cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); - cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); - cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); - cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); - cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); - cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); - cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); - cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); - cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); - cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); - cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); - } -} +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class RivalsOfIxalan extends ExpansionSet { + + private static final RivalsOfIxalan instance = new RivalsOfIxalan(); + + public static RivalsOfIxalan getInstance() { + return instance; + } + + private RivalsOfIxalan() { + super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); + this.blockName = "Ixalan"; + this.parentSet = Ixalan.getInstance(); + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); + cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); + cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); + cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); + cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); + cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); + cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); + cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); + cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); + cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); + cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); + cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); + } +} From 28cd0e34432186b26f82ca1383fee570e3a1df91 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 3 Jan 2018 15:14:40 +0400 Subject: [PATCH 47/54] [RIX] Added Forerunner of the Heralds --- .../mage/cards/h/ForerunnerOfTheHeralds.java | 104 +++++++++++ Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 173 +++++++++--------- 2 files changed, 191 insertions(+), 86 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java diff --git a/Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java b/Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java new file mode 100644 index 00000000000..e9317207a5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java @@ -0,0 +1,104 @@ +/* + * 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.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterBySubtypeCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author JayDi85 + */ +public class ForerunnerOfTheHeralds extends CardImpl { + + private static final FilterPermanent filterYourMerfolk = new FilterPermanent("Merfolk"); + + static { + filterYourMerfolk.add(new AnotherPredicate()); + filterYourMerfolk.add(new ControllerPredicate(TargetController.YOU)); + filterYourMerfolk.add(new SubtypePredicate(SubType.MERFOLK)); + } + + public ForerunnerOfTheHeralds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + + // When Forerunner of the Heralds enters the battlefield, you may search your library for a Merfolk card, reveal it, then shuffle your library and put that card on top of it. + this.addAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary( + new FilterBySubtypeCard(SubType.MERFOLK)), + true, true + ), + true + ) + ); + + // Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on Forerunner of the Heralds. + this.addAbility( + new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), + filterYourMerfolk, + false, null, true + ) + ); + } + + public ForerunnerOfTheHeralds(final ForerunnerOfTheHeralds card) { + super(card); + } + + @Override + public ForerunnerOfTheHeralds copy() { + return new ForerunnerOfTheHeralds(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index aa575ac8533..de3c54e7281 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -1,86 +1,87 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author fireshoes - */ -public class RivalsOfIxalan extends ExpansionSet { - - private static final RivalsOfIxalan instance = new RivalsOfIxalan(); - - public static RivalsOfIxalan getInstance() { - return instance; - } - - private RivalsOfIxalan() { - super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); - this.blockName = "Ixalan"; - this.parentSet = Ixalan.getInstance(); - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - - cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); - cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); - cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); - cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); - cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); - cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); - cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); - cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); - cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); - cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); - cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); - cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); - cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); - cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); - cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); - cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); - cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); - cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); - cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); - cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); - cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); - cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); - cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); - cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); - } -} +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class RivalsOfIxalan extends ExpansionSet { + + private static final RivalsOfIxalan instance = new RivalsOfIxalan(); + + public static RivalsOfIxalan getInstance() { + return instance; + } + + private RivalsOfIxalan() { + super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); + this.blockName = "Ixalan"; + this.parentSet = Ixalan.getInstance(); + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); + cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); + cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); + cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); + cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); + cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); + cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.h.ForerunnerOfTheHeralds.class)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); + cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); + cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); + cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); + cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); + cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); + } +} From 723cc87f0964ef05f6e8889c3db7cd45e6048de0 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 3 Jan 2018 15:19:53 +0400 Subject: [PATCH 48/54] Typos --- Mage.Sets/src/mage/cards/{h => f}/ForerunnerOfTheHeralds.java | 2 +- Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Mage.Sets/src/mage/cards/{h => f}/ForerunnerOfTheHeralds.java (99%) diff --git a/Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java similarity index 99% rename from Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java rename to Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java index e9317207a5c..c4c2b202908 100644 --- a/Mage.Sets/src/mage/cards/h/ForerunnerOfTheHeralds.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java @@ -25,7 +25,7 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ -package mage.cards.h; +package mage.cards.f; import java.util.UUID; import mage.MageInt; diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index de3c54e7281..dbf2a6dacc7 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -65,7 +65,7 @@ public class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.h.ForerunnerOfTheHeralds.class)); + cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheHeralds.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); From 59159338e829b0f5c131333da9ef046b1e091b2b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 13:00:31 +0100 Subject: [PATCH 49/54] [Rix] Added 6 cards. --- .../mage/cards/k/KumenaTyrantOfOrazca.java | 107 ++++++++++++++++++ .../src/mage/cards/k/KumenasAwakening.java | 69 +++++++++++ .../src/mage/cards/l/LegionLieutenant.java | 78 +++++++++++++ .../src/mage/cards/s/SeafloorOracle.java | 71 ++++++++++++ .../mage/cards/s/SecretsOfTheGoldenCity.java | 67 +++++++++++ .../src/mage/cards/s/SkymarcherAspirant.java | 80 +++++++++++++ .../src/mage/cards/t/TheImmortalSun.java | 3 +- .../src/mage/cards/v/VeteranWarleader.java | 8 +- Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 8 +- 9 files changed, 487 insertions(+), 4 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java create mode 100644 Mage.Sets/src/mage/cards/k/KumenasAwakening.java create mode 100644 Mage.Sets/src/mage/cards/l/LegionLieutenant.java create mode 100644 Mage.Sets/src/mage/cards/s/SeafloorOracle.java create mode 100644 Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java create mode 100644 Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java diff --git a/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java b/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java new file mode 100644 index 00000000000..6e2c7d575d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java @@ -0,0 +1,107 @@ +/* + * 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.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 + */ +public class KumenaTyrantOfOrazca extends CardImpl { + + private static final FilterControlledPermanent filterAnother = new FilterControlledPermanent("another untapped Merfolk you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Merfolk you control"); + private static final FilterControlledPermanent filterAll = new FilterControlledPermanent("Merfolk you control"); + + static { + filterAnother.add(new AnotherPredicate()); + filterAnother.add(new SubtypePredicate(SubType.MERFOLK)); + filterAnother.add(Predicates.not(new TappedPredicate())); + + filter.add(new SubtypePredicate(SubType.MERFOLK)); + filter.add(Predicates.not(new TappedPredicate())); + + filter.add(new SubtypePredicate(SubType.MERFOLK)); + } + + public KumenaTyrantOfOrazca(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new CantBeBlockedSourceEffect(Duration.EndOfTurn), + new TapTargetCost(new TargetControlledPermanent(1, 1, filterAnother, true)))); + + // Tap three untapped Merfolk you control: Draw a card. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new DrawCardSourceControllerEffect(1), + new TapTargetCost(new TargetControlledPermanent(3, 3, filter, true)))); + + // Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filterAll), + new TapTargetCost(new TargetControlledPermanent(5, 5, filter, true)))); + + } + + public KumenaTyrantOfOrazca(final KumenaTyrantOfOrazca card) { + super(card); + } + + @Override + public KumenaTyrantOfOrazca copy() { + return new KumenaTyrantOfOrazca(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KumenasAwakening.java b/Mage.Sets/src/mage/cards/k/KumenasAwakening.java new file mode 100644 index 00000000000..eb49b0f20df --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KumenasAwakening.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.AscendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; + +/** + * + * @author LevelX2 + */ +public class KumenasAwakening extends CardImpl { + + public KumenasAwakening(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + + // Ascend (If you control ten or more permenants, you get the city's blessing for the rest of the game.) + this.addAbility(new AscendAbility()); + + // At the beginning of your upkeep, each player draws a card. If you have the city's blessing, instead only you draw a card. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new DrawCardAllEffect(1), CitysBlessingCondition.instance, + "each player draws a card. If you have the city's blessing, instead only you draw a card"), + TargetController.YOU, false)); + } + + public KumenasAwakening(final KumenasAwakening card) { + super(card); + } + + @Override + public KumenasAwakening copy() { + return new KumenasAwakening(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LegionLieutenant.java b/Mage.Sets/src/mage/cards/l/LegionLieutenant.java new file mode 100644 index 00000000000..455b5e4d697 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LegionLieutenant.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LevelX2 + */ +public class LegionLieutenant extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Vampires you control"); + + static { + filter.add(new SubtypePredicate(SubType.VAMPIRE)); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public LegionLieutenant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Other Vampires you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); + } + + public LegionLieutenant(final LegionLieutenant card) { + super(card); + } + + @Override + public LegionLieutenant copy() { + return new LegionLieutenant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeafloorOracle.java b/Mage.Sets/src/mage/cards/s/SeafloorOracle.java new file mode 100644 index 00000000000..0cec34fe3f9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeafloorOracle.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; + +/** + * + * @author LevelX2 + */ +public class SeafloorOracle extends CardImpl { + + public SeafloorOracle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever a Merfolk you controls deals combat damage to a player, draw a card. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + new FilterControlledCreaturePermanent(SubType.MERFOLK, "a Merfolk you control"), + false, SetTargetPointer.NONE, true)); + + } + + public SeafloorOracle(final SeafloorOracle card) { + super(card); + } + + @Override + public SeafloorOracle copy() { + return new SeafloorOracle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java b/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java new file mode 100644 index 00000000000..175a0ce9662 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.effects.keyword.AscendEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author LevelX2 + */ +public class SecretsOfTheGoldenCity extends CardImpl { + + public SecretsOfTheGoldenCity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}"); + + // Ascend + this.getSpellAbility().addEffect(new AscendEffect()); + + // Draw two cards. If you have the city's blessing, draw three cards instead. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DiscardControllerEffect(3), + new DiscardControllerEffect(2), + CitysBlessingCondition.instance, + "Draw two cards. If you have the city's blessing, draw three cards instead")); + } + + public SecretsOfTheGoldenCity(final SecretsOfTheGoldenCity card) { + super(card); + } + + @Override + public SecretsOfTheGoldenCity copy() { + return new SecretsOfTheGoldenCity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java b/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java new file mode 100644 index 00000000000..e46b9588c38 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.AscendAbility; +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; + +/** + * + * @author LevelX2 + */ +public class SkymarcherAspirant extends CardImpl { + + public SkymarcherAspirant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Ascend + this.addAbility(new AscendAbility()); + + // Skymarcher Aspirant has flying as long as you have the city's blessing. + ContinuousEffect boostSource = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, + "{this} has flying as long as you have the city's blessing"); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + this.addAbility(ability); + } + + public SkymarcherAspirant(final SkymarcherAspirant card) { + super(card); + } + + @Override + public SkymarcherAspirant copy() { + return new SkymarcherAspirant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java index f8505beebff..4b1fa19c8a7 100644 --- a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java +++ b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java @@ -65,7 +65,8 @@ public class TheImmortalSun extends CardImpl { // Players can't activate planeswalkers' loyalty abilities. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TheImmortalSunCantActivateEffect())); // At the beginning of your draw step, draw an additional card. - this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false)); + this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1) + .setText("draw an additional card"), TargetController.YOU, false)); // Spells you cast cost {1} less to cast. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(new FilterCard("Spells you cast"), 1))); // Creatures you control get +1/+1. diff --git a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java index 1bddfe44a9c..83aa9c70d40 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java +++ b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java @@ -50,8 +50,11 @@ import mage.choices.Choice; import mage.choices.ChoiceImpl; import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetControlledPermanent; @@ -62,15 +65,16 @@ import mage.target.common.TargetControlledPermanent; */ public class VeteranWarleader extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another untapped Ally you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("another untapped Ally you control"); static { filter.add(new AnotherPredicate()); filter.add(new SubtypePredicate(SubType.ALLY)); + filter.add(Predicates.not(new TappedPredicate())); } public VeteranWarleader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.subtype.add(SubType.ALLY); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index aa575ac8533..0ad60063f8d 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -63,14 +63,20 @@ public class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); - cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); + cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); + cards.add(new SetCardInfo("Kumena's Awakening", 42, Rarity.RARE, mage.cards.k.KumenasAwakening.class)); + cards.add(new SetCardInfo("Kumena, Tyrant of Orazca", 162, Rarity.MYTHIC, mage.cards.k.KumenaTyrantOfOrazca.class)); + cards.add(new SetCardInfo("Legion Lieutenant", 163, Rarity.UNCOMMON, mage.cards.l.LegionLieutenant.class)); cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Seafloor Oracle", 51, Rarity.RARE, mage.cards.s.SeafloorOracle.class)); + cards.add(new SetCardInfo("Secrets of the Golden City", 52, Rarity.COMMON, mage.cards.s.SecretsOfTheGoldenCity.class)); cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Skymarcher Aspirant", 21, Rarity.UNCOMMON, mage.cards.s.SkymarcherAspirant.class)); cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); From cdbaea4a80190b72491d733853cc7fe45a4eebeb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 13:11:29 +0100 Subject: [PATCH 50/54] Updated mtg-cards-data.txt with spoilers 72/196 of 2018-01-03 13:10 CET --- Utils/mtg-cards-data.txt | 43 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index fa74794d1dd..32351e3f80c 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -32696,37 +32696,46 @@ Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G} to yo Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to target creature or player, where X is the number of Gremlins you control.| Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)| Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.| -Famished Paladin|Rivals of Ixalan|8|U|{1}{W}|Creature - Vampire Knight|3|3|Famished Paladin does not untap during your untap step.$Whenever you gain life, untap Famished Paladin.| -Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to it's toughness.| -Glorious Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$As Glorious Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.| -Skynarcher Aspirant|Rivals of Ixalan|21|U|{W}|Creature - Vampire Soldier|2|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Skymarcher Aspirant has flying as long as you have the city's blessing| +Mysterious End|Rivals of Ixalan|1|U|{1}{W}|Enchantment|||When Mysterious end enters the battlefield, exile target creature with converted mana cost 3 or less an opponent controls.$When Mysterious end leaves the battlefield, target opponent create a 3/3 green Dinosaur creature token with trample.| +Bishop of Binding|Rivals of Ixalan|2|R|{3}{W}|Creature - Vampire Cleric|1|1|When Bishop of Binding enters the battlefield, exile target creature an opponent controls until Bishop of Binding leaves the battlefield.$Whenever Bishop of Binding attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card.| +Famished Paladin|Rivals of Ixalan|8|U|{1}{W}|Creature - Vampire Knight|3|3|Famished Paladin doesn't untap during your untap step.$Whenever you gain life, untap Famished Paladin.| +Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to its toughness.| +Radiant Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$As Radiant Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.| +Skymarcher Aspirant|Rivals of Ixalan|21|U|{W}|Creature - Vampire Soldier|2|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Skymarcher Aspirant has flying as long as you have the city's blessing.| +Sphinx's Decree|Rivals of Ixalan|24|R|{1}{W}|Sorcery|||Each opponent can't cast instant or sorcery spells during that player's next turn.| Temple Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source would deal damage to another Dinosaur you control, prevent all but 1 of that damage.| Zetalpa, Primal Dawn|Rivals of Ixalan|30|R|{6}{W}{W}|Legendary Creature - Elder Dinosaur|4|8|Flying, double strike, vigilance, trample, indestructible| Admiral's Order|Rivals of Ixalan|31|R|{1}{U}{U}|Instant|||Raid — If you attacked with a creature this turn, you may pay {U} rather than pay this spell's mana cost.$Counter target spell.| -Aquatic Incursion|Rivals of Ixalan|32|U|{3}{U}|Enchantment|||When Aquatic Incursion enters the battlefield, create two 1/1 blue Merfolk creature tokens with hexproof.${3}{U}: Target Merfolk can't be blocked this turn.| +Aquatic Incursion|Rivals of Ixalan|32|U|{3}{U}|Enchantment|||When Aquatic Incursion enters the battlefield, create two 1/1 blue Merfolk creature tokens with hexproof. (They can't be the target of spells or abilities your opponents control.)${3}{U}: Target Merfolk can't be blocked this turn.| Induced Amnesia|Rivals of Ixalan|40|R|{2}{U}|Enchantment|||When Induced Amnesia enters the battlefield, target player exiles all the cards in his or her hand face down, then draws that many cards.$When Induced Amnesia is put into a graveyard from the battlefield, return the exiled cards to their owner's hand.| -Kumena's Awakening|Rivals of Ixalan|42|R|{2}{U}{U}|Enchantment|||Ascend (If you control ten or more permenants, you get the city's blessing for the rest of the game.)$At the beginning of your upkeep, each player draws a card. If you have the city's blessing, instead only you draw a card.| +Kumena's Awakening|Rivals of Ixalan|42|R|{2}{U}{U}|Enchantment|||Ascend (If you control ten or more permenants, you get the city's blessing for the rest of the game.)$At the beginning of your upkeep, each player draws a card. If you have the city's blessing, instead only you draw a card.| River Darter|Rivals of Ixalan|47|C|{2}{U}|Creature - Merfolk Warrior|2|3|River Darter can't be blocked by Dinosaurs.| -Seafloor Oracle|Rivals of Ixalan|51|R|{2}{W}{W}|Creature - Merfolk Wizard|2|3|Whenever a Merfolk you controls deals combat damage to a player, draw a card.| +Seafloor Oracle|Rivals of Ixalan|51|R|{2}{U}{U}|Creature - Merfolk Wizard|2|3|Whenever a Merfolk you controls deals combat damage to a player, draw a card.| Secrets of the Golden City|Rivals of Ixalan|52|C|{1}{U}{U}|Sorcery|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Draw two cards. If you have the city's blessing, draw three cards instead.| Silvergill Adept|Rivals of Ixalan|53|U|{1}{U}|Creature - Merfolk Wizard|2|1|As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.$When Silvergill Adept enters the battlefield, draw a card.| -Timestream Navigator|Rivals of Ixalan|59|M|{1}{U}|Creature - Human Pirate Wizard|1|1|Ascend (If you control ten or more permanents, you gain The City's Blessing for the rest of the game.)${2}{U}{U}, {T}, Put Timestream Navigator at the bottom of its owner's library: Take an extra turn after this one. Activate this ability only if you have The City's Blessing.| +Timestream Navigator|Rivals of Ixalan|59|M|{1}{U}|Creature - Human Pirate Wizard|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)${2}{U}{U}, {T}, Put Timestream Navigator on the bottom of its owner's library: Take an extra turn after this one. Activate this ability only if you have the city's blessing.| +Dead Man's Chest|Rivals of Ixalan|66|R|{1}{B}|Enchantment - Aura|||Enchant creature an opponent controls$When enchanted creature dies, exile cards equal to its power from the top of its owner's library. You may cast nonland cards from among them as long as they remain exiled, and you may spend mana as though it were mana of any type to cast those spells.| Dusk Charger|Rivals of Ixalan|69|C|{3}{B}|Creature - Horse|3|3|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Dusk Charger gets +2/+2 as long as you have the city's blessing.| +Forerunner of the Coalition|Rivals of Ixalan|72|U|{2}{B}|Creature - Human Pirate|2|2|When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Pirate enters the battlefield under your control, each opponent loses 1 life.| Ravenous Chupacabra|Rivals of Ixalan|82|U|{2}{B}{B}|Creature - Beast Horror|2|2|When Ravenous Chupacabra enters the battlefield, destroy target creature an opponent controls.| Tetzimoc, Primal Death|Rivals of Ixalan|86|R|{4}{B}{B}|Legendary Creature - Elder Dinosaur|6|6|Deathtouch${B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.$When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it.| Vona's Hunger|Rivals of Ixalan|90|R|{2}{B}|Instant|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Each opponent sacrifices a creature. If you have the city's blessing, instead each opponent sacrifices half the creatures he or she controls rounded up.| Brass's Bounty|Rivals of Ixalan|94|R|{6}{R}|Sorcery|||For each land you control, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| -Daring Buccaneer|Rivals of Ixalan|98|U|{R}|Creature - Human Pirate|2|2|As an additional cost to cast Daring Buccaneer, reveal a Pirate card from your hand or pay 2.| +Daring Buccaneer|Rivals of Ixalan|98|U|{R}|Creature - Human Pirate|2|2|As an additional cost to cast Daring Buccaneer, reveal a Pirate card from your hand or pay {2}.| Etali, Primal Storm|Rivals of Ixalan|100|R|{4}{R}{R}|Legendary Creature - Elder Dinosaur|6|6|Whenever Etali, Primal Storm attacks, exile the top card of each player's library, then you may cast any number of nonland cards exiled this way without paying their mana costs.| +Forerunner of the Empire|Rivals of Ixalan|102|U|{3}{R}|Creature - Human Soldier|1|3|When Forerunner of the Empire enters the battlefield, you may search your library for a Dinosaur card, reveal it, then shuffle your library and put that card on top of it.$Whenever a Dinosaur enters the battlefield under your control, you may have Forerunner of the Empire deal 1 damage to each creature.| Form of the Dinosaur|Rivals of Ixalan|103|R|{4}{R}{R}|Enchantment|||When Form of the Dinosaur enters the battlefield, your life total becomes 15.$At the beginning of your upkeep, Form of the Dinosaur deals 15 damage to target creature an opponent controls and that creature deals damage equal to its power to you.| Frilled Deathspitter|Rivals of Ixalan|104|C|{2}{R}|Creature - Dinosaur|3|2|Enrage — Whenever Frilled Deathspitter is dealt damage, it deals 2 damage to target opponent.| +Pirate's Pillage|Rivals of Ixalan|109|U|{3}{R}|Sorcery|||As an additional cost to cast Pirate's Pillage, discard a card.$Draw two cards and create two colorless Treasure artifacts with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| Swaggering Corsair|Rivals of Ixalan|119|C|{2}{R}|Creature - Human Pirate|2|2|Raid — Swaggering Corsair enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn.| -Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step, unless you have the City's blessing.| +Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step unless you have the city's blessing.| +Deeproot Elite|Rivals of Ixalan|127|R|{1}{G}|Creature - Merfolk Warrior|1|1|Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on target Merfolk you control.| Enter the Unknown|Rivals of Ixalan|128|U|{G}|Sorcery|||Target creature you control explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.) $You may play an additional land this turn.| +Forerunner of the Heralds|Rivals of Ixalan|129|U|{3}{G}|Creature - Merfolk Scout|3|2|When Forerunner of the Heralds enters the battlefield, you may search your library for a Merfolk card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on Forerunner of the Heralds.| Ghalta, Primal Hunger|Rivals of Ixalan|130|R|{1}{0}{G}{G}|Legendary Creature - Elder Dinosaur|12|12|Ghalta, Primal Hunger costs {X} less to cast, where X is the total power of creatures you control.$Trample| -Jadelight Ranger|Rivals of Ixalan|136|R|{1}{G}{G}|Creature - Merfolk Scout|2|1|When Jadelight Ranger enters the battlefield it explores, then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process) | -Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)| -Swift Warden|Rivals of Ixalan|146|U|{1}{G}{G}|Creature - Merfolk Warrior|3|3|When Swift Warden enters the battlefield, target Merfolk you control gains hexproof until end of turn. (It can't be the target of spells or abilities your opponents control)| +Jadelight Ranger|Rivals of Ixalan|136|R|{1}{G}{G}|Creature - Merfolk Scout|2|1|When Jadelight Ranger enters the battlefield it explores, then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process.) | +Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)| +Swift Warden|Rivals of Ixalan|146|U|{1}{G}{G}|Creature - Merfolk Warrior|3|3|When Swift Warden enters the battlefield, target Merfolk you control gains hexproof until end of turn. (It can't be the target of spells or abilities your opponents control.)| Tendershoot Dryad|Rivals of Ixalan|147|R|{4}{G}|Creature - Dryad|2|2|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$At the beginning of each upkeep, create a 1/1 green Saproling creature token.$Saprolings you control get +2/+2 as long as you have the city's blessing.| Thrashing Brontodon|Rivals of Ixalan|148|U|{1}{G}{G}|Creature - Dinosaur|3|4|{1}, Sacrificing Thrashing Brontodon: Destroy target artifact or enchantment.| World Shaper|Rivals of Ixalan|151|R|{3}{G}|Creature - Merfolk Shaman|3|3|Whenever World Shaper attacks, you may put the top three cards of your library into your graveyard.$When World Shaper dies, put all land cards from your graveyard onto the battlefield tapped.| @@ -32736,15 +32745,18 @@ Elenda, the Dusk Rose|Rivals of Ixalan|157|M|{2}{W}{B}|Legendary Creature - Vamp Huatli, Radiant Champion|Rivals of Ixalan|159|M|{2}{G}{W}|Legendary Planeswalker - Huatli|3|+1: Put a loyalty counter on Huatli, Radiant Champion for each creature you control.$-1: Target creature gets +X/+X until end of turn, where X is the number of creatures you control.$-8: You get an emblem with "Whenever a creature enters the battlefield under your control, you may draw a card."| Journey to Eternity|Rivals of Ixalan|160|R|{1}{B}{G}|Legendary Enchantment - Aura|||Enchant creature you control$When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control.| Atzal, Cave of Eternity|Rivals of Ixalan|160|R||Legendary Land|||(Transforms from Journey to Eternity.)${t}: Add one mana of any color to your mana pool.${3}{B}{G}, {t}: Return target creature card from your graveyard to the battlefield.| -Kumena, Tyrant of Orzca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| +Kumena, Tyrant of Orzaca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| Legion Lieutenant|Rivals of Ixalan|163|U|{W}{B}|Creature - Vampire Knight|2|2|Other Vampires you control get +1/+1.| -Merfolk Mistbender|Rivals of Ixalan|164|U|{G}{U}|Creature - Merfolk Shaman|2|2|Other Merfolk you control get +1/+1.| +Merfolk Mistbinder|Rivals of Ixalan|164|U|{G}{U}|Creature - Merfolk Shaman|2|2|Other Merfolk you control get +1/+1.| +Profane Procession|Rivals of Ixalan|166|R|{1}{W}{B}|Legendary Enchantment|||{3}{W}{B}: Exile target creature. Then if there are three or more cards exiled with Profane Procession, transform it.| +Tomb of the Dusk Rose|Rivals of Ixalan|166|R||Legendary Land|||{T}: Add one mana of any color to your mana pool.${2}{W}{B},{T} : Put a creature card exiled with this permanent onto the battlefield under your control.| Storm the Vault|Rivals of Ixalan|173|R|{2}{U}{R}|Legendary Enchantment|||Whenever one or more creatures you control deal combat damage to a player, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool."$At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault.| Vault of Catlacan|Rivals of Ixalan|173|R||Legendary Land|||(Transforms from Storm the Vault.)${T}: Add one mana of any color to your mana pool.${T}: Add {U} to your mana pool for each artifact you control.| Awakened Amalgam|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control.| Captain's Hook|Rivals of Ixalan|177|R|{3}|Artifact - Equipment|||Equipped creature gets +2/+0, has menace, and is a Pirate in addition to its other creature types.$Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent.$Equip {1}| Gleaming Barrier|Rivals of Ixalan|178|C|{2}|Artifact Creature - Wall|0|4|Defender$When Gleaming Barrier dies, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate planeswalkers' loyalty abilities.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.| +Silent Gravestone|Rivals of Ixalan|182|R|{1}|Artifact|||Cards in graveyards can't be the targets of spells or abilities.${4}, {t}: Exile Silent Gravestone and all cards from all graveyards. Draw a card.| Evolving Wilds|Rivals of Ixalan|186|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| Vraska, Scheming Gorgon|Rivals of Ixalan|197|M|{4}{B}{B}|Legendary Planeswalker - Vraska|5|+2: Creatures you control get +1/+0 until end of turn.$-3: Destroy target creature.$-10: Until end of turn, creatures you control gain deathtouch and "Whenever this creature deals damage to an opponent, that player loses the game."| Vampire Champion|Rivals of Ixalan|198|C|{3}{B}|Creature - Vampire Soldier|3|3|Deathtouch (Any amount of damage this deals to a creature is enough to destroy it.)| @@ -32755,6 +32767,7 @@ Angrath's Ambusher|Rivals of Ixalan|202|U|{2}{B}|Creature - Orc Pirate|2|3|Angra Swab Goblin|Rivals of Ixalan|203|C|{1}{R}|Creature - Goblin Pirate|2|2|| Angrath's Fury|Rivals of Ixalan|204|R|{3}{B}{R}|Sorcery|||Destroy target creature. Angrath's Fury deals 3 damage to target player. You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle it.| Cinder Barrens|Rivals of Ixalan|205|C||Land|||Cinder Barrens enters the battlefield tapped.${T}: Add {B} or {R} to your mana pool.| +Forerunner of the Legion|Rivals of Ixalan|9|U|{9}|Creature - Vampire Knight|2|2|When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Vampire enters the battlefield under your control, target creature gets +1/+1 until end of turn. Amateur Auteur|Unstable|3|C|{1}{W}|Creature - Human|2|2|Sacrifice Amateur Auteur: Destroy target enchantment.| Angelic Rocket|Unstable|139|R|{8}|Host Creature - Angel|4|4|Flying$When this creature enters the battlefield, you may destroy target nonland permanent.| As Luck Would Have It|Unstable|102|R|{G}|Enchantment|||Hexproof$Whenever you roll a die, put a number of luck counters on As Luck Would Have It equal to the result. Then is there are 100 or more luck counters on As Luck Would Have It, you win the game. (Count both rolls if you reroll a die.)| From 62dd91a5d56c78a2eed446ecdc7c1ba07c02858b Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Wed, 3 Jan 2018 17:53:28 +0400 Subject: [PATCH 51/54] [RIX] Added 3 cards, fixes --- .../cards/f/ForerunnerOfTheCoalition.java | 96 +++++++++++++++++++ .../mage/cards/f/ForerunnerOfTheEmpire.java | 94 ++++++++++++++++++ .../mage/cards/f/ForerunnerOfTheHeralds.java | 29 ++---- .../mage/cards/f/ForerunnerOfTheLegion.java | 93 ++++++++++++++++++ Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 3 + 5 files changed, 296 insertions(+), 19 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java create mode 100644 Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java create mode 100644 Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java new file mode 100644 index 00000000000..4c82be50879 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java @@ -0,0 +1,96 @@ +/* + * 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.Ability; +import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.common.FilterBySubtypeCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author JayDi85 + */ +public class ForerunnerOfTheCoalition extends CardImpl { + + private static final FilterCreaturePermanent filterAnotherPirate = new FilterCreaturePermanent(SubType.PIRATE, "another " + SubType.PIRATE.toString()); + static { + filterAnotherPirate.add(new AnotherPredicate()); + filterAnotherPirate.add(new ControllerPredicate(TargetController.YOU)); + } + + public ForerunnerOfTheCoalition(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it. + this.addAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary(new FilterBySubtypeCard(SubType.PIRATE)), + true, + true + ), + true + ) + ); + + // Whenever another Pirate enters the battlefield under your control, each opponent loses 1 life. + Ability ability = new CreatureEntersBattlefieldTriggeredAbility( + Zone.BATTLEFIELD, + new LoseLifeOpponentsEffect(1), + filterAnotherPirate, + false, + false); + this.addAbility(ability); + } + + public ForerunnerOfTheCoalition(final ForerunnerOfTheCoalition card) { + super(card); + } + + @Override + public ForerunnerOfTheCoalition copy() { + return new ForerunnerOfTheCoalition(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java new file mode 100644 index 00000000000..2e772a96e9f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java @@ -0,0 +1,94 @@ +/* + * 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.Ability; +import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.common.FilterBySubtypeCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author JayDi85 + */ +public class ForerunnerOfTheEmpire extends CardImpl { + + private static final FilterCreaturePermanent filterAnyDinosaur = new FilterCreaturePermanent(SubType.DINOSAUR, SubType.DINOSAUR.toString()); + static { + filterAnyDinosaur.add(new ControllerPredicate(TargetController.YOU)); + } + + public ForerunnerOfTheEmpire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Forerunner of the Empire enters the battlefield, you may search your library for a Dinosaur card, reveal it, then shuffle your library and put that card on top of it. + this.addAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary(new FilterBySubtypeCard(SubType.DINOSAUR)), + true, + true + ), + true + ) + ); + + // Whenever a Dinosaur enters the battlefield under your control, you may have Forerunner of the Empire deal 1 damage to each creature. + Ability ability = new CreatureEntersBattlefieldTriggeredAbility( + Zone.BATTLEFIELD, + new DamageAllEffect(1, new FilterCreaturePermanent()), + filterAnyDinosaur, + true, + false); + this.addAbility(ability); + } + + public ForerunnerOfTheEmpire(final ForerunnerOfTheEmpire card) { + super(card); + } + + @Override + public ForerunnerOfTheEmpire copy() { + return new ForerunnerOfTheEmpire(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java index c4c2b202908..c6445274c21 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java @@ -29,7 +29,8 @@ package mage.cards.f; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; @@ -38,11 +39,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterBySubtypeCard; -import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCardInLibrary; @@ -53,12 +52,10 @@ import mage.target.common.TargetCardInLibrary; */ public class ForerunnerOfTheHeralds extends CardImpl { - private static final FilterPermanent filterYourMerfolk = new FilterPermanent("Merfolk"); - + private static final FilterPermanent filterAnotherMerfolk = new FilterPermanent(SubType.MERFOLK, SubType.MERFOLK.toString()); static { - filterYourMerfolk.add(new AnotherPredicate()); - filterYourMerfolk.add(new ControllerPredicate(TargetController.YOU)); - filterYourMerfolk.add(new SubtypePredicate(SubType.MERFOLK)); + filterAnotherMerfolk.add(new AnotherPredicate()); + filterAnotherMerfolk.add(new ControllerPredicate(TargetController.YOU)); } public ForerunnerOfTheHeralds(UUID ownerId, CardSetInfo setInfo) { @@ -74,23 +71,17 @@ public class ForerunnerOfTheHeralds extends CardImpl { this.addAbility( new EntersBattlefieldTriggeredAbility( new SearchLibraryPutOnLibraryEffect( - new TargetCardInLibrary( - new FilterBySubtypeCard(SubType.MERFOLK)), - true, true + new TargetCardInLibrary(new FilterBySubtypeCard(SubType.MERFOLK)), + true, + true ), true ) ); // Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on Forerunner of the Heralds. - this.addAbility( - new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), - filterYourMerfolk, - false, null, true - ) - ); + Ability ability = new EntersBattlefieldControlledTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filterAnotherMerfolk); + this.addAbility(ability); } public ForerunnerOfTheHeralds(final ForerunnerOfTheHeralds card) { diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java new file mode 100644 index 00000000000..dd19791b0e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.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.f; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterBySubtypeCard; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author JayDi85 + */ +public class ForerunnerOfTheLegion extends CardImpl { + + private static final FilterPermanent filterAnotherVampire = new FilterPermanent(SubType.VAMPIRE, "another " + SubType.VAMPIRE.toString()); + static { + filterAnotherVampire.add(new AnotherPredicate()); + filterAnotherVampire.add(new ControllerPredicate(TargetController.YOU)); + } + + public ForerunnerOfTheLegion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it. + this.addAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary(new FilterBySubtypeCard(SubType.VAMPIRE)), + true, + true + ), + true + ) + ); + + // Whenever another Vampire enters the battlefield under your control, target creature gets +1/+1 until end of turn. + Ability ability = new EntersBattlefieldControlledTriggeredAbility(new BoostTargetEffect(1,1, Duration.EndOfTurn), filterAnotherVampire); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ForerunnerOfTheLegion(final ForerunnerOfTheLegion card) { + super(card); + } + + @Override + public ForerunnerOfTheLegion copy() { + return new ForerunnerOfTheLegion(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 901ee0eb19c..5f97eadcf3c 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -65,7 +65,10 @@ public class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Forerunner of the Coalition", 72, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheCoalition.class)); + cards.add(new SetCardInfo("Forerunner of the Empire", 102, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheEmpire.class)); cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheHeralds.class)); + cards.add(new SetCardInfo("Forerunner of the Legion", 9, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheLegion.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); From 3d50213f46a8a63e43e467c569fabf379a1ce1b7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 15:36:43 +0100 Subject: [PATCH 52/54] Added test for #4333 - problem non-reproducible yet. --- .../cards/triggers/MasterOfCrueltiesTest.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/triggers/MasterOfCrueltiesTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MasterOfCrueltiesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MasterOfCrueltiesTest.java new file mode 100644 index 00000000000..cabc4a974e8 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/MasterOfCrueltiesTest.java @@ -0,0 +1,80 @@ +/* + * 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 org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class MasterOfCrueltiesTest extends CardTestPlayerBase { + + /* + The ability of an Alesha-resurrected Master of Cruelties triggered in an EDH game despite being blocked by a creature. + */ + @Test + public void testMasterWasAleshaAnimated() { + // First strike + // Whenever Alesha, Who Smiles at Death attacks, you may pay {W/B}{W/B}. If you do, return target creature card with power 2 or less from your graveyard to the battlefield tapped and attacking. + addCard(Zone.BATTLEFIELD, playerB, "Alesha, Who Smiles at Death"); // 3/2 + + // First strike + // Deathtouch + // Master of Cruelties can only attack alone. + // Whenever Master of Cruelties attacks a player and isn't blocked, that player's life total becomes 1. Master of Cruelties assigns no combat damage this combat. + addCard(Zone.GRAVEYARD, playerB, "Master of Cruelties"); // 1/4 + + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + + attack(2, playerB, "Alesha, Who Smiles at Death"); + setChoice(playerB, "Yes"); + addTarget(playerB, "Master of Cruelties"); + + block(2, playerA, "Silvercoat Lion", "Master of Cruelties"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, "Master of Cruelties", 1); + assertTapped("Master of Cruelties", true); + assertTapped("Alesha, Who Smiles at Death", true); + + assertLife(playerA, 17); + assertLife(playerB, 20); + + assertGraveyardCount(playerA, "Silvercoat Lion", 1); + + } + +} From 547c7078bfec11d5d7e951724aaaa63992252676 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 18:02:27 +0100 Subject: [PATCH 53/54] [Rix] Added 6 cards. --- .../src/mage/cards/a/AdmiralBeckettBrass.java | 3 +- .../cards/f/ForerunnerOfTheCoalition.java | 34 ++- .../mage/cards/f/ForerunnerOfTheEmpire.java | 7 +- Mage.Sets/src/mage/cards/g/GroundSeal.java | 49 +---- Mage.Sets/src/mage/cards/m/BafflingEnd.java | 86 ++++++++ .../src/mage/cards/m/MerfolkMistbinder.java | 78 +++++++ .../src/mage/cards/p/PathToDiscovery.java | 64 ++++++ .../src/mage/cards/p/PiratesPillage.java | 65 ++++++ .../src/mage/cards/s/SilentGravestone.java | 73 +++++++ Mage.Sets/src/mage/cards/s/SphinxsDecree.java | 153 ++++++++++++++ .../src/mage/cards/u/UnderworldCerberus.java | 56 +---- Mage.Sets/src/mage/sets/RivalsOfIxalan.java | 198 +++++++++--------- .../CantBeTargetedCardsGraveyardsEffect.java | 82 ++++++++ .../effects/keyword/ExploreSourceEffect.java | 48 ++--- .../effects/keyword/ExploreTargetEffect.java | 60 ++++++ 15 files changed, 811 insertions(+), 245 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/m/BafflingEnd.java create mode 100644 Mage.Sets/src/mage/cards/m/MerfolkMistbinder.java create mode 100644 Mage.Sets/src/mage/cards/p/PathToDiscovery.java create mode 100644 Mage.Sets/src/mage/cards/p/PiratesPillage.java create mode 100644 Mage.Sets/src/mage/cards/s/SilentGravestone.java create mode 100644 Mage.Sets/src/mage/cards/s/SphinxsDecree.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedCardsGraveyardsEffect.java create mode 100644 Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java index cd291187e89..a7406924a9c 100644 --- a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java +++ b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java @@ -27,6 +27,7 @@ */ package mage.cards.a; +import java.util.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; @@ -48,8 +49,6 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetNonlandPermanent; import mage.watchers.Watcher; -import java.util.*; - /** * * @author TheElk801 diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java index 4c82be50879..95762b8f5a2 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java @@ -30,15 +30,15 @@ package mage.cards.f; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterBySubtypeCard; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCardInLibrary; @@ -49,7 +49,8 @@ import mage.target.common.TargetCardInLibrary; */ public class ForerunnerOfTheCoalition extends CardImpl { - private static final FilterCreaturePermanent filterAnotherPirate = new FilterCreaturePermanent(SubType.PIRATE, "another " + SubType.PIRATE.toString()); + private static final FilterPermanent filterAnotherPirate = new FilterPermanent(SubType.PIRATE, "another " + SubType.PIRATE.toString()); + static { filterAnotherPirate.add(new AnotherPredicate()); filterAnotherPirate.add(new ControllerPredicate(TargetController.YOU)); @@ -64,24 +65,15 @@ public class ForerunnerOfTheCoalition extends CardImpl { this.toughness = new MageInt(2); // When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it. - this.addAbility( - new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutOnLibraryEffect( - new TargetCardInLibrary(new FilterBySubtypeCard(SubType.PIRATE)), - true, - true - ), - true - ) - ); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutOnLibraryEffect( + new TargetCardInLibrary(new FilterBySubtypeCard(SubType.PIRATE)), + true, true), true)); // Whenever another Pirate enters the battlefield under your control, each opponent loses 1 life. - Ability ability = new CreatureEntersBattlefieldTriggeredAbility( - Zone.BATTLEFIELD, - new LoseLifeOpponentsEffect(1), - filterAnotherPirate, - false, - false); + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(1), + filterAnotherPirate, false); this.addAbility(ability); } @@ -93,4 +85,4 @@ public class ForerunnerOfTheCoalition extends CardImpl { public ForerunnerOfTheCoalition copy() { return new ForerunnerOfTheCoalition(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java index 2e772a96e9f..b17846dcfb6 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java @@ -34,9 +34,9 @@ import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.common.FilterBySubtypeCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -49,6 +49,7 @@ import mage.target.common.TargetCardInLibrary; public class ForerunnerOfTheEmpire extends CardImpl { private static final FilterCreaturePermanent filterAnyDinosaur = new FilterCreaturePermanent(SubType.DINOSAUR, SubType.DINOSAUR.toString()); + static { filterAnyDinosaur.add(new ControllerPredicate(TargetController.YOU)); } @@ -76,7 +77,7 @@ public class ForerunnerOfTheEmpire extends CardImpl { // Whenever a Dinosaur enters the battlefield under your control, you may have Forerunner of the Empire deal 1 damage to each creature. Ability ability = new CreatureEntersBattlefieldTriggeredAbility( Zone.BATTLEFIELD, - new DamageAllEffect(1, new FilterCreaturePermanent()), + new DamageAllEffect(1, new FilterCreaturePermanent()).setText("have {this} deal 1 damage to each creature"), filterAnyDinosaur, true, false); @@ -91,4 +92,4 @@ public class ForerunnerOfTheEmpire extends CardImpl { public ForerunnerOfTheEmpire copy() { return new ForerunnerOfTheEmpire(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GroundSeal.java b/Mage.Sets/src/mage/cards/g/GroundSeal.java index 24e9a9b1f90..f3f5817665a 100644 --- a/Mage.Sets/src/mage/cards/g/GroundSeal.java +++ b/Mage.Sets/src/mage/cards/g/GroundSeal.java @@ -28,21 +28,14 @@ package mage.cards.g; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.StackObject; /** * @author jeffwadsworth @@ -52,12 +45,11 @@ public class GroundSeal extends CardImpl { public GroundSeal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); - // When Ground Seal enters the battlefield, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); // Cards in graveyards can't be the targets of spells or abilities. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GroundSealEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedCardsGraveyardsEffect())); } public GroundSeal(final GroundSeal card) { @@ -69,40 +61,3 @@ public class GroundSeal extends CardImpl { return new GroundSeal(this); } } - -class GroundSealEffect extends ContinuousRuleModifyingEffectImpl { - - public GroundSealEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "Cards in graveyards can't be the targets of spells or abilities"; - } - - public GroundSealEffect(final GroundSealEffect effect) { - super(effect); - } - - @Override - public GroundSealEffect copy() { - return new GroundSealEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.TARGET) { - Card targetCard = game.getCard(event.getTargetId()); - StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); - if (targetCard != null && stackObject != null) { - Zone zone = game.getState().getZone(targetCard.getId()); - if (zone != null && zone == Zone.GRAVEYARD) { - return true; - } - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/BafflingEnd.java b/Mage.Sets/src/mage/cards/m/BafflingEnd.java new file mode 100644 index 00000000000..2c43e9888a7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/BafflingEnd.java @@ -0,0 +1,86 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.permanent.token.DinosaurToken; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +/** + * + * @author LevelX2 + */ +public class BafflingEnd extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost 3 or less an opponent controls"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public BafflingEnd(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + // When Mysterious end enters the battlefield, exile target creature with converted mana cost 3 or less an opponent controls. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // When Mysterious end leaves the battlefield, target opponent create a 3/3 green Dinosaur creature token with trample. + ability = new LeavesBattlefieldTriggeredAbility(new CreateTokenTargetEffect(new DinosaurToken()), false); + Target target = new TargetOpponent(); + ability.addTarget(target); + this.addAbility(ability); + + } + + public BafflingEnd(final BafflingEnd card) { + super(card); + } + + @Override + public BafflingEnd copy() { + return new BafflingEnd(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MerfolkMistbinder.java b/Mage.Sets/src/mage/cards/m/MerfolkMistbinder.java new file mode 100644 index 00000000000..9b58c8dc889 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MerfolkMistbinder.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +/** + * + * @author LevelX2 + */ +public class MerfolkMistbinder extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Merfolk you control"); + + static { + filter.add(new SubtypePredicate(SubType.MERFOLK)); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public MerfolkMistbinder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Other Merfolk you control get +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); + } + + public MerfolkMistbinder(final MerfolkMistbinder card) { + super(card); + } + + @Override + public MerfolkMistbinder copy() { + return new MerfolkMistbinder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PathToDiscovery.java b/Mage.Sets/src/mage/cards/p/PathToDiscovery.java new file mode 100644 index 00000000000..8156d52e650 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PathToDiscovery.java @@ -0,0 +1,64 @@ +/* + * 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.p; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.keyword.ExploreTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.StaticFilters; + +/** + * + * @author LevelX2 + */ +public class PathToDiscovery extends CardImpl { + + public PathToDiscovery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.) + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new ExploreTargetEffect(), + StaticFilters.FILTER_CONTROLLED_A_CREATURE, false, SetTargetPointer.PERMANENT, null)); + + } + + public PathToDiscovery(final PathToDiscovery card) { + super(card); + } + + @Override + public PathToDiscovery copy() { + return new PathToDiscovery(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PiratesPillage.java b/Mage.Sets/src/mage/cards/p/PiratesPillage.java new file mode 100644 index 00000000000..294f37a42d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiratesPillage.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.p; + +import java.util.UUID; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.TreasureToken; + +/** + * + * @author LevelX2 + */ +public class PiratesPillage extends CardImpl { + + public PiratesPillage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // As an additional cost to cast Pirate's Pillage, discard a card. + this.getSpellAbility().addCost(new DiscardCardCost(true)); + + // Draw two cards and create two colorless Treasure artifacts with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool." + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken(), 2) + .setText("and create two colorless Treasure artifacts with \"{T}, Sacrifice this artifact: Add one mana of any color to your mana pool")); + } + + public PiratesPillage(final PiratesPillage card) { + super(card); + } + + @Override + public PiratesPillage copy() { + return new PiratesPillage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilentGravestone.java b/Mage.Sets/src/mage/cards/s/SilentGravestone.java new file mode 100644 index 00000000000..b0167986749 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilentGravestone.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.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.abilities.effects.common.ExileSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class SilentGravestone extends CardImpl { + + public SilentGravestone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // Cards in graveyards can't be the targets of spells or abilities. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedCardsGraveyardsEffect())); + + // {4}, {t}: Exile Silent Gravestone and all cards from all graveyards. Draw a card. + Ability ability = new SimpleActivatedAbility(new ExileSourceEffect(), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addEffect(new ExileGraveyardAllPlayersEffect().setText("and all cards from all graveyards")); + ability.addEffect(new DrawCardSourceControllerEffect(1)); + this.addAbility(ability); + } + + public SilentGravestone(final SilentGravestone card) { + super(card); + } + + @Override + public SilentGravestone copy() { + return new SilentGravestone(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SphinxsDecree.java b/Mage.Sets/src/mage/cards/s/SphinxsDecree.java new file mode 100644 index 00000000000..827eef47829 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxsDecree.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.s; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 + */ +public class SphinxsDecree extends CardImpl { + + public SphinxsDecree(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); + + // Each opponent can't cast instant or sorcery spells during that player's next turn. + this.getSpellAbility().addEffect(new SphinxsDecreeEffect()); + } + + public SphinxsDecree(final SphinxsDecree card) { + super(card); + } + + @Override + public SphinxsDecree copy() { + return new SphinxsDecree(this); + } +} + +class SphinxsDecreeEffect extends OneShotEffect { + + public SphinxsDecreeEffect() { + super(Outcome.Benefit); + this.staticText = "Each opponent can't cast instant or sorcery spells during that player's next turn"; + } + + public SphinxsDecreeEffect(final SphinxsDecreeEffect effect) { + super(effect); + } + + @Override + public SphinxsDecreeEffect copy() { + return new SphinxsDecreeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + ContinuousEffect effect = new SphinxsDecreeCantCastEffect(); + effect.setTargetPointer(new FixedTarget(opponentId)); + game.addEffect(effect, source); + } + return true; + } +} + +class SphinxsDecreeCantCastEffect extends ContinuousRuleModifyingEffectImpl { + + int playersNextTurn; + + public SphinxsDecreeCantCastEffect() { + super(Duration.Custom, Outcome.Detriment); + staticText = "You can't cast instant or sorcery spells during this turn"; + playersNextTurn = 0; + } + + public SphinxsDecreeCantCastEffect(final SphinxsDecreeCantCastEffect effect) { + super(effect); + this.playersNextTurn = effect.playersNextTurn; + } + + @Override + public SphinxsDecreeCantCastEffect copy() { + return new SphinxsDecreeCantCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't cast instant or sorcery spells this turn (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + UUID opponentId = getTargetPointer().getFirst(game, source); + if (game.getActivePlayerId().equals(opponentId)) { + if (playersNextTurn == 0) { + playersNextTurn = game.getTurnNum(); + } + if (playersNextTurn == game.getTurnNum()) { + if (opponentId.equals(event.getPlayerId())) { + MageObject object = game.getObject(event.getSourceId()); + if (event.getType() == GameEvent.EventType.CAST_SPELL) { + if (object.isInstant() || object.isSorcery()) { + return true; + } + } + } + } else { + discard(); + } + } else if (playersNextTurn > 0) { + discard(); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderworldCerberus.java b/Mage.Sets/src/mage/cards/u/UnderworldCerberus.java index 7fe7b0a3f31..bbf9cab2f5e 100644 --- a/Mage.Sets/src/mage/cards/u/UnderworldCerberus.java +++ b/Mage.Sets/src/mage/cards/u/UnderworldCerberus.java @@ -32,22 +32,16 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect; import mage.abilities.effects.common.ExileSourceEffect; import mage.abilities.effects.common.ReturnToHandFromGraveyardAllEffect; import mage.abilities.effects.common.combat.CantBeBlockedByOneEffect; -import mage.cards.Card; 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.Zone; import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.StackObject; /** * @@ -56,7 +50,7 @@ import mage.game.stack.StackObject; public class UnderworldCerberus extends CardImpl { public UnderworldCerberus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); this.subtype.add(SubType.HOUND); this.power = new MageInt(6); @@ -64,10 +58,10 @@ public class UnderworldCerberus extends CardImpl { // Underworld Cerberus can't be blocked except by three or more creatures. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByOneEffect(3))); - + // Cards in graveyards can't be the targets of spells or abilities. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UnderworldCerberusEffect())); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedCardsGraveyardsEffect())); + // When Underworld Cerberus dies, exile it and each player returns all creature cards from his or her graveyard to his or her hand. Ability ability = new DiesTriggeredAbility(new ExileSourceEffect()); ability.addEffect(new ReturnToHandFromGraveyardAllEffect(new FilterCreatureCard("creature cards"))); @@ -83,43 +77,3 @@ public class UnderworldCerberus extends CardImpl { return new UnderworldCerberus(this); } } - -class UnderworldCerberusEffect extends ContinuousRuleModifyingEffectImpl { - - public UnderworldCerberusEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "Cards in graveyards can't be the targets of spells or abilities"; - } - - public UnderworldCerberusEffect(final UnderworldCerberusEffect effect) { - super(effect); - } - - @Override - public UnderworldCerberusEffect copy() { - return new UnderworldCerberusEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.TARGET; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - Card targetCard = game.getCard(event.getTargetId()); - StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); - if (targetCard != null && stackObject != null) { - Zone zone = game.getState().getZone(targetCard.getId()); - if (zone != null && zone == Zone.GRAVEYARD) { - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 5f97eadcf3c..72919af296a 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -1,96 +1,102 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author fireshoes - */ -public class RivalsOfIxalan extends ExpansionSet { - - private static final RivalsOfIxalan instance = new RivalsOfIxalan(); - - public static RivalsOfIxalan getInstance() { - return instance; - } - - private RivalsOfIxalan() { - super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); - this.blockName = "Ixalan"; - this.parentSet = Ixalan.getInstance(); - this.hasBoosters = true; - this.hasBasicLands = false; - this.numBoosterLands = 1; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 8; - - cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); - cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); - cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); - cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); - cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); - cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); - cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); - cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); - cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); - cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); - cards.add(new SetCardInfo("Forerunner of the Coalition", 72, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheCoalition.class)); - cards.add(new SetCardInfo("Forerunner of the Empire", 102, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheEmpire.class)); - cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheHeralds.class)); - cards.add(new SetCardInfo("Forerunner of the Legion", 9, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheLegion.class)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); - cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); - cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); - cards.add(new SetCardInfo("Kumena's Awakening", 42, Rarity.RARE, mage.cards.k.KumenasAwakening.class)); - cards.add(new SetCardInfo("Kumena, Tyrant of Orazca", 162, Rarity.MYTHIC, mage.cards.k.KumenaTyrantOfOrazca.class)); - cards.add(new SetCardInfo("Legion Lieutenant", 163, Rarity.UNCOMMON, mage.cards.l.LegionLieutenant.class)); - cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); - cards.add(new SetCardInfo("Seafloor Oracle", 51, Rarity.RARE, mage.cards.s.SeafloorOracle.class)); - cards.add(new SetCardInfo("Secrets of the Golden City", 52, Rarity.COMMON, mage.cards.s.SecretsOfTheGoldenCity.class)); - cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); - cards.add(new SetCardInfo("Skymarcher Aspirant", 21, Rarity.UNCOMMON, mage.cards.s.SkymarcherAspirant.class)); - cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); - cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); - cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); - cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); - cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); - cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); - cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); - cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); - cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); - cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); - } -} +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class RivalsOfIxalan extends ExpansionSet { + + private static final RivalsOfIxalan instance = new RivalsOfIxalan(); + + public static RivalsOfIxalan getInstance() { + return instance; + } + + private RivalsOfIxalan() { + super("Rivals of Ixalan", "RIX", ExpansionSet.buildDate(2018, 1, 19), SetType.EXPANSION); + this.blockName = "Ixalan"; + this.parentSet = Ixalan.getInstance(); + this.hasBoosters = true; + this.hasBasicLands = false; + this.numBoosterLands = 1; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Angrath's Ambusher", 202, Rarity.UNCOMMON, mage.cards.a.AngrathsAmbusher.class)); + cards.add(new SetCardInfo("Angrath's Fury", 204, Rarity.RARE, mage.cards.a.AngrathsFury.class)); + cards.add(new SetCardInfo("Angrath, Minotaur Pirate", 201, Rarity.MYTHIC, mage.cards.a.AngrathMinotaurPirate.class)); + cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); + cards.add(new SetCardInfo("Brass's Bounty", 94, Rarity.RARE, mage.cards.b.BrasssBounty.class)); + cards.add(new SetCardInfo("Buffling End", 1, Rarity.UNCOMMON, mage.cards.m.BafflingEnd.class)); + cards.add(new SetCardInfo("Captain's Hook", 177, Rarity.RARE, mage.cards.c.CaptainsHook.class)); + cards.add(new SetCardInfo("Cinder Barrens", 205, Rarity.RARE, mage.cards.c.CinderBarrens.class)); + cards.add(new SetCardInfo("Dusk Charger", 69, Rarity.COMMON, mage.cards.d.DuskCharger.class)); + cards.add(new SetCardInfo("Elenda, the Dusk Rose", 157, Rarity.MYTHIC, mage.cards.e.ElendaTheDuskRose.class)); + cards.add(new SetCardInfo("Evolving Wilds", 186, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Forerunner of the Coalition", 72, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheCoalition.class)); + cards.add(new SetCardInfo("Forerunner of the Empire", 102, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheEmpire.class)); + cards.add(new SetCardInfo("Forerunner of the Heralds", 129, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheHeralds.class)); + cards.add(new SetCardInfo("Forerunner of the Legion", 9, Rarity.UNCOMMON, mage.cards.f.ForerunnerOfTheLegion.class)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Glorious Destiny", 18, Rarity.RARE, mage.cards.g.GloriousDestiny.class)); + cards.add(new SetCardInfo("Jadelight Ranger", 136, Rarity.RARE, mage.cards.j.JadelightRanger.class)); + cards.add(new SetCardInfo("Journey to Eternity", 160, Rarity.RARE, mage.cards.j.JourneyToEternity.class)); + cards.add(new SetCardInfo("Kumena's Awakening", 42, Rarity.RARE, mage.cards.k.KumenasAwakening.class)); + cards.add(new SetCardInfo("Kumena, Tyrant of Orazca", 162, Rarity.MYTHIC, mage.cards.k.KumenaTyrantOfOrazca.class)); + cards.add(new SetCardInfo("Legion Lieutenant", 163, Rarity.UNCOMMON, mage.cards.l.LegionLieutenant.class)); + cards.add(new SetCardInfo("Merfolk Mistbinder", 164, Rarity.UNCOMMON, mage.cards.m.MerfolkMistbinder.class)); + cards.add(new SetCardInfo("Paladin of Atonement", 16, Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); + cards.add(new SetCardInfo("Path to Discovery", 142, Rarity.RARE, mage.cards.p.PathToDiscovery.class)); + cards.add(new SetCardInfo("Pirate's Pillage", 109, Rarity.UNCOMMON, mage.cards.p.PiratesPillage.class)); + cards.add(new SetCardInfo("Seafloor Oracle", 51, Rarity.RARE, mage.cards.s.SeafloorOracle.class)); + cards.add(new SetCardInfo("Secrets of the Golden City", 52, Rarity.COMMON, mage.cards.s.SecretsOfTheGoldenCity.class)); + cards.add(new SetCardInfo("Silent Gravestone", 182, Rarity.RARE, mage.cards.s.SilentGravestone.class)); + cards.add(new SetCardInfo("Silvergill Adept", 53, Rarity.UNCOMMON, mage.cards.s.SilvergillAdept.class)); + cards.add(new SetCardInfo("Skymarcher Aspirant", 21, Rarity.UNCOMMON, mage.cards.s.SkymarcherAspirant.class)); + cards.add(new SetCardInfo("Sphinx's Decree", 24, Rarity.RARE, mage.cards.s.SphinxsDecree.class)); + cards.add(new SetCardInfo("Storm the Vault", 173, Rarity.RARE, mage.cards.s.StormTheVault.class)); + cards.add(new SetCardInfo("Swab Goblin", 203, Rarity.COMMON, mage.cards.s.SwabGoblin.class)); + cards.add(new SetCardInfo("Tetzimoc, Primal Death", 86, Rarity.RARE, mage.cards.t.TetzimocPrimalDeath.class)); + cards.add(new SetCardInfo("The Immortal Sun", 180, Rarity.MYTHIC, mage.cards.t.TheImmortalSun.class)); + cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); + cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); + cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); + cards.add(new SetCardInfo("Vraska's Conquistador", 199, Rarity.UNCOMMON, mage.cards.v.VraskasConquistador.class)); + cards.add(new SetCardInfo("Vraska's Scorn", 200, Rarity.RARE, mage.cards.v.VraskasScorn.class)); + cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); + cards.add(new SetCardInfo("Zetalpa, Primal Dawn", 30, Rarity.RARE, mage.cards.z.ZetalpaPrimalDawn.class)); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedCardsGraveyardsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedCardsGraveyardsEffect.java new file mode 100644 index 00000000000..c7d6151057d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedCardsGraveyardsEffect.java @@ -0,0 +1,82 @@ +/* + * 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; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.StackObject; + +/** + * + * @author LevelX2 + */ +public class CantBeTargetedCardsGraveyardsEffect extends ContinuousRuleModifyingEffectImpl { + + public CantBeTargetedCardsGraveyardsEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Cards in graveyards can't be the targets of spells or abilities"; + } + + public CantBeTargetedCardsGraveyardsEffect(final CantBeTargetedCardsGraveyardsEffect effect) { + super(effect); + } + + @Override + public CantBeTargetedCardsGraveyardsEffect copy() { + return new CantBeTargetedCardsGraveyardsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TARGET; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Card targetCard = game.getCard(event.getTargetId()); + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (targetCard != null && stackObject != null) { + Zone zone = game.getState().getZone(targetCard.getId()); + if (zone != null && zone == Zone.GRAVEYARD) { + return true; + } + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java index a64c9aad8cd..06030eb1a18 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreSourceEffect.java @@ -27,17 +27,15 @@ */ package mage.abilities.effects.keyword; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -49,15 +47,11 @@ import mage.players.Player; */ public class ExploreSourceEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCard("a land card"); - - static { - filter.add(new CardTypePredicate(CardType.LAND)); - } + public static final String RULE_TEXT = "it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.)"; public ExploreSourceEffect() { super(Outcome.Benefit); - this.staticText = "it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.)"; + this.staticText = RULE_TEXT; } public ExploreSourceEffect(final ExploreSourceEffect effect) { @@ -71,35 +65,39 @@ public class ExploreSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + return explorePermanent(game, source.getSourceId(), source); + } + + public static boolean explorePermanent(Game game, UUID permanentId, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(permanentId); + if (permanent == null) { return false; } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EXPLORED, source.getSourceId(), source.getSourceId(), source.getControllerId())); - if (player.getLibrary().hasCards()) { - Card card = player.getLibrary().getFromTop(game); + Player permanentController = game.getPlayer(source.getControllerId()); + if (permanentController == null) { + return false; + } + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EXPLORED, permanentId, source.getSourceId(), permanent.getControllerId())); + if (permanentController.getLibrary().hasCards()) { + Card card = permanentController.getLibrary().getFromTop(game); Cards cards = new CardsImpl(); cards.add(card); - player.revealCards("Explored card", cards, game); + permanentController.revealCards("Explored card", cards, game); if (card != null) { - if (filter.match(card, game)) { + if (card.isLand()) { card.moveToZone(Zone.HAND, source.getSourceId(), game, true); } else { - if (creature != null) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); - } - if (player.chooseUse(Outcome.Neutral, "Put " + card.getLogName() + " in your graveyard?", source, game)) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + if (permanentController.chooseUse(Outcome.Neutral, "Put " + card.getLogName() + " in your graveyard?", source, game)) { card.moveToZone(Zone.GRAVEYARD, source.getSourceId(), game, true); - game.informPlayers(player.getLogName() + " puts " + card.getLogName() + " into their graveyard."); + game.informPlayers(permanentController.getLogName() + " puts " + card.getLogName() + " into their graveyard."); } else { - game.informPlayers(player.getLogName() + " leaves " + card.getLogName() + " on top of their library."); + game.informPlayers(permanentController.getLogName() + " leaves " + card.getLogName() + " on top of their library."); } } } - return true; } - return false; + return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java new file mode 100644 index 00000000000..8c204656f94 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ExploreTargetEffect.java @@ -0,0 +1,60 @@ +/* + * 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.keyword; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; + +/** + * + * @author LevelX2 + */ +public class ExploreTargetEffect extends OneShotEffect { + + public ExploreTargetEffect() { + super(Outcome.Benefit); + this.staticText = ExploreSourceEffect.RULE_TEXT; + } + + public ExploreTargetEffect(final ExploreTargetEffect effect) { + super(effect); + } + + @Override + public ExploreTargetEffect copy() { + return new ExploreTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return ExploreSourceEffect.explorePermanent(game, getTargetPointer().getFirst(game, source), source); + } + +} From b448f83c8cb18959824730a843267d7c7bd2925b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 3 Jan 2018 18:05:32 +0100 Subject: [PATCH 54/54] Updated mtg-cards-data.txt with spoilers 82/196 of 2018-01-03 18:00 CET --- Utils/mtg-cards-data.txt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 32351e3f80c..37527bb3fc6 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -32696,9 +32696,10 @@ Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G} to yo Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to target creature or player, where X is the number of Gremlins you control.| Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)| Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.| -Mysterious End|Rivals of Ixalan|1|U|{1}{W}|Enchantment|||When Mysterious end enters the battlefield, exile target creature with converted mana cost 3 or less an opponent controls.$When Mysterious end leaves the battlefield, target opponent create a 3/3 green Dinosaur creature token with trample.| +Baffling End|Rivals of Ixalan|1|U|{1}{W}|Enchantment|||When Baffling End enters the battlefield, exile target creature an opponent controls with converted mana cost 3 or less.$When Baffling End leaves the battlefield, target opponent create a 3/3 green Dinosaur creature token with trample.| Bishop of Binding|Rivals of Ixalan|2|R|{3}{W}|Creature - Vampire Cleric|1|1|When Bishop of Binding enters the battlefield, exile target creature an opponent controls until Bishop of Binding leaves the battlefield.$Whenever Bishop of Binding attacks, target Vampire gets +X/+X until end of turn, where X is the power of the exiled card.| Famished Paladin|Rivals of Ixalan|8|U|{1}{W}|Creature - Vampire Knight|3|3|Famished Paladin doesn't untap during your untap step.$Whenever you gain life, untap Famished Paladin.| +Forerunner of the Legion|Rivals of Ixalan|9|U|{2}{W}|Creature - Vampire Knight|2|2|When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Vampire enters the battlefield under your control, target creature gets +1/+1 until end of turn.| Paladin of Atonement|Rivals of Ixalan|16|R|{1}{W}|Creature - Vampire Knight|1|1|At the beginning of each upkeep, if you lost life last turn, put a +1/+1 counter on Paladin of Atonement.$When Paladin of Atonement dies, you gain life equal to its toughness.| Radiant Destiny|Rivals of Ixalan|18|R|{2}{W}|Enchantment|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$As Radiant Destiny enters the battlefield, choose a creature type.$Creatures you control of the chosen type get +1/+1. They have vigilance as long as you have the city's blessing.| Skymarcher Aspirant|Rivals of Ixalan|21|U|{W}|Creature - Vampire Soldier|2|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Skymarcher Aspirant has flying as long as you have the city's blessing.| @@ -32707,6 +32708,7 @@ Temple Altisaur|Rivals of Ixalan|28|R|{4}{W}|Creature - Dinosaur|3|4|If a source Zetalpa, Primal Dawn|Rivals of Ixalan|30|R|{6}{W}{W}|Legendary Creature - Elder Dinosaur|4|8|Flying, double strike, vigilance, trample, indestructible| Admiral's Order|Rivals of Ixalan|31|R|{1}{U}{U}|Instant|||Raid — If you attacked with a creature this turn, you may pay {U} rather than pay this spell's mana cost.$Counter target spell.| Aquatic Incursion|Rivals of Ixalan|32|U|{3}{U}|Enchantment|||When Aquatic Incursion enters the battlefield, create two 1/1 blue Merfolk creature tokens with hexproof. (They can't be the target of spells or abilities your opponents control.)${3}{U}: Target Merfolk can't be blocked this turn.| +Flood of Recollection|Rivals of Ixalan|38|U|{U}{U}|Sorcery|||Return Target instant or sorcery card from your graveyard to your hand. Exile Flood of Recollection.| Induced Amnesia|Rivals of Ixalan|40|R|{2}{U}|Enchantment|||When Induced Amnesia enters the battlefield, target player exiles all the cards in his or her hand face down, then draws that many cards.$When Induced Amnesia is put into a graveyard from the battlefield, return the exiled cards to their owner's hand.| Kumena's Awakening|Rivals of Ixalan|42|R|{2}{U}{U}|Enchantment|||Ascend (If you control ten or more permenants, you get the city's blessing for the rest of the game.)$At the beginning of your upkeep, each player draws a card. If you have the city's blessing, instead only you draw a card.| River Darter|Rivals of Ixalan|47|C|{2}{U}|Creature - Merfolk Warrior|2|3|River Darter can't be blocked by Dinosaurs.| @@ -32714,8 +32716,10 @@ Seafloor Oracle|Rivals of Ixalan|51|R|{2}{U}{U}|Creature - Merfolk Wizard|2|3|Wh Secrets of the Golden City|Rivals of Ixalan|52|C|{1}{U}{U}|Sorcery|||Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Draw two cards. If you have the city's blessing, draw three cards instead.| Silvergill Adept|Rivals of Ixalan|53|U|{1}{U}|Creature - Merfolk Wizard|2|1|As an additional cost to cast Silvergill Adept, reveal a Merfolk card from your hand or pay {3}.$When Silvergill Adept enters the battlefield, draw a card.| Timestream Navigator|Rivals of Ixalan|59|M|{1}{U}|Creature - Human Pirate Wizard|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)${2}{U}{U}, {T}, Put Timestream Navigator on the bottom of its owner's library: Take an extra turn after this one. Activate this ability only if you have the city's blessing.| +~Warsail Marauder|Rivals of Ixalan|60|R|{1}{U}|Creature - Human Pirate|2|1|Flying$Whenever Warsail Marauder attacks, target creature loses all abilities and has base power and toughness 0/1 until end of turn.| Dead Man's Chest|Rivals of Ixalan|66|R|{1}{B}|Enchantment - Aura|||Enchant creature an opponent controls$When enchanted creature dies, exile cards equal to its power from the top of its owner's library. You may cast nonland cards from among them as long as they remain exiled, and you may spend mana as though it were mana of any type to cast those spells.| Dusk Charger|Rivals of Ixalan|69|C|{3}{B}|Creature - Horse|3|3|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Dusk Charger gets +2/+2 as long as you have the city's blessing.| +Dusk Legion Zealot|Rivals of Ixalan|70|C|{1}{B}|Creature - Vampire Soldier|1|1|When Dusk Legion Zealot enters the battlefield, you draw a card and you lose 1 life.| Forerunner of the Coalition|Rivals of Ixalan|72|U|{2}{B}|Creature - Human Pirate|2|2|When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Pirate enters the battlefield under your control, each opponent loses 1 life.| Ravenous Chupacabra|Rivals of Ixalan|82|U|{2}{B}{B}|Creature - Beast Horror|2|2|When Ravenous Chupacabra enters the battlefield, destroy target creature an opponent controls.| Tetzimoc, Primal Death|Rivals of Ixalan|86|R|{4}{B}{B}|Legendary Creature - Elder Dinosaur|6|6|Deathtouch${B}, Reveal Tetzimoc, Primal Death from your hand: Put a prey counter on target creature. Activate this ability only during your turn.$When Tetzimoc, Primal Death enters the battlefield, destroy each creature your opponents control with a prey counter on it.| @@ -32727,34 +32731,41 @@ Forerunner of the Empire|Rivals of Ixalan|102|U|{3}{R}|Creature - Human Soldier| Form of the Dinosaur|Rivals of Ixalan|103|R|{4}{R}{R}|Enchantment|||When Form of the Dinosaur enters the battlefield, your life total becomes 15.$At the beginning of your upkeep, Form of the Dinosaur deals 15 damage to target creature an opponent controls and that creature deals damage equal to its power to you.| Frilled Deathspitter|Rivals of Ixalan|104|C|{2}{R}|Creature - Dinosaur|3|2|Enrage — Whenever Frilled Deathspitter is dealt damage, it deals 2 damage to target opponent.| Pirate's Pillage|Rivals of Ixalan|109|U|{3}{R}|Sorcery|||As an additional cost to cast Pirate's Pillage, discard a card.$Draw two cards and create two colorless Treasure artifacts with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| +Rekindling Phoenix|Rivals of Ixalan|111|M|{2}{R}{R}|Creature - Phoenix|4|3|Flying$When Rekindling Phoenix dies, create a 0/1 red Elemental creature token with "At the beginning of your upkeep, sacrifice this creature and return target card named Rekindling Phoenix from your graveyard to the battlefield. It gains haste until end of turn."| Swaggering Corsair|Rivals of Ixalan|119|C|{2}{R}|Creature - Human Pirate|2|2|Raid — Swaggering Corsair enters the battlefield with a +1/+1 counter on it if you attacked with a creature this turn.| Tilonalli's Summoner|Rivals of Ixalan|121|R|{1}{R}|Creature - Human Shaman|1|1|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 Elemental creature tokens tapped and attacking. Exile them at the beginning of the next end step unless you have the city's blessing.| +Cherished Hatchling|Rivals of Ixalan|124|U|{1}{G}|Creature - Dinosaur|2|1|When Cherished Hatchling dies, you may cast Dinosaur spells this turn as though they had flash, and whenever you cast a Dinosaur spell this turn, it gains "When this creature enters the battlefield, you may have it fight another target creature."| Deeproot Elite|Rivals of Ixalan|127|R|{1}{G}|Creature - Merfolk Warrior|1|1|Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on target Merfolk you control.| Enter the Unknown|Rivals of Ixalan|128|U|{G}|Sorcery|||Target creature you control explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard.) $You may play an additional land this turn.| Forerunner of the Heralds|Rivals of Ixalan|129|U|{3}{G}|Creature - Merfolk Scout|3|2|When Forerunner of the Heralds enters the battlefield, you may search your library for a Merfolk card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Merfolk enters the battlefield under your control, put a +1/+1 counter on Forerunner of the Heralds.| Ghalta, Primal Hunger|Rivals of Ixalan|130|R|{1}{0}{G}{G}|Legendary Creature - Elder Dinosaur|12|12|Ghalta, Primal Hunger costs {X} less to cast, where X is the total power of creatures you control.$Trample| Jadelight Ranger|Rivals of Ixalan|136|R|{1}{G}{G}|Creature - Merfolk Scout|2|1|When Jadelight Ranger enters the battlefield it explores, then it explores again. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on this creature, then put the card back or put it into your graveyard. Then repeat this process.) | Path to Discovery|Rivals of Ixalan|142|R|{3}{G}|Enchantment|||Whenever a creature enters the battlefield under your control, it explores. (Reveal the top card of your library. Put that card into your hand if it's a land. Otherwise, put a +1/+1 counter on the creature, then put the card back or put it into your graveyard.)| +Polyraptor|Rivals of Ixalan|144|M|{6}{G}{G}|Creature - Dinosaur|5|5|Enrage — Whenever Polyraptor is dealt damage, create a token that is a copy of Polyraptor| Swift Warden|Rivals of Ixalan|146|U|{1}{G}{G}|Creature - Merfolk Warrior|3|3|When Swift Warden enters the battlefield, target Merfolk you control gains hexproof until end of turn. (It can't be the target of spells or abilities your opponents control.)| Tendershoot Dryad|Rivals of Ixalan|147|R|{4}{G}|Creature - Dryad|2|2|Ascend (If you control ten or more permanents, you get the city's blessing for the rest of the game.)$At the beginning of each upkeep, create a 1/1 green Saproling creature token.$Saprolings you control get +2/+2 as long as you have the city's blessing.| Thrashing Brontodon|Rivals of Ixalan|148|U|{1}{G}{G}|Creature - Dinosaur|3|4|{1}, Sacrificing Thrashing Brontodon: Destroy target artifact or enchantment.| World Shaper|Rivals of Ixalan|151|R|{3}{G}|Creature - Merfolk Shaman|3|3|Whenever World Shaper attacks, you may put the top three cards of your library into your graveyard.$When World Shaper dies, put all land cards from your graveyard onto the battlefield tapped.| Angrath, the Flame-Chained|Rivals of Ixalan|152|M|{3}{B}{R}|Legendary Planeswalker - Angrath|4|+1: Each opponent discards a card and loses 2 life.$-3: Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. Sacrifice it at the beginning of the next end step if it has converted mana cost 3 or less.$-8: Each opponent loses life equal to the number of cards in his or her graveyard.| Atzocan Seer|Rivals of Ixalan|153|U|{1}{G}{W}|Creature - Human Druid|2|3|{t}: Add one mana of any color to your manan pool.$Sacrifice Atzocan Seer: Return target Dinosaur card from your graveyard to your hand.| +Azor, the Lawbringer|Rivals of Ixalan|154|M|{2}{W}{W}{U}{U}|Legendary Creature - Sphinx|6|6|Flying$When Azor, the Lawbringer enters the battlefield, each opponent can't cast instant and sorcery spells during that player's next turn.$Whenever Azor attacks, you may pay {X}{W}{U}{U}. If you do, you may gain X life and draw X cards.| Elenda, the Dusk Rose|Rivals of Ixalan|157|M|{2}{W}{B}|Legendary Creature - Vampire Knight|1|1|Lifelink$Whenever another creature dies, put a +1/+1 counter on Elenda, the Dusk Rose.$When Elenda dies, create X 1/1 white Vampire creature tokens with lifelink, where X is Elenda's power| Huatli, Radiant Champion|Rivals of Ixalan|159|M|{2}{G}{W}|Legendary Planeswalker - Huatli|3|+1: Put a loyalty counter on Huatli, Radiant Champion for each creature you control.$-1: Target creature gets +X/+X until end of turn, where X is the number of creatures you control.$-8: You get an emblem with "Whenever a creature enters the battlefield under your control, you may draw a card."| Journey to Eternity|Rivals of Ixalan|160|R|{1}{B}{G}|Legendary Enchantment - Aura|||Enchant creature you control$When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control.| Atzal, Cave of Eternity|Rivals of Ixalan|160|R||Legendary Land|||(Transforms from Journey to Eternity.)${t}: Add one mana of any color to your mana pool.${3}{B}{G}, {t}: Return target creature card from your graveyard to the battlefield.| -Kumena, Tyrant of Orzaca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| +Kumena, Tyrant of Orzca|Rivals of Ixalan|162|M|{1}{G}{U}|Legendary Creature - Merfolk Shaman|2|4|Tap another untapped Merfolk you control: Kumena, Tyrant of Orzca can't be blocked this turn.$Tap three untapped Merfolk you control: Draw a card.$Tap five untapped Merfolk you control: Put a +1/+1 counter on each Merfolk you control.| Legion Lieutenant|Rivals of Ixalan|163|U|{W}{B}|Creature - Vampire Knight|2|2|Other Vampires you control get +1/+1.| Merfolk Mistbinder|Rivals of Ixalan|164|U|{G}{U}|Creature - Merfolk Shaman|2|2|Other Merfolk you control get +1/+1.| Profane Procession|Rivals of Ixalan|166|R|{1}{W}{B}|Legendary Enchantment|||{3}{W}{B}: Exile target creature. Then if there are three or more cards exiled with Profane Procession, transform it.| Tomb of the Dusk Rose|Rivals of Ixalan|166|R||Legendary Land|||{T}: Add one mana of any color to your mana pool.${2}{W}{B},{T} : Put a creature card exiled with this permanent onto the battlefield under your control.| +Protean Raider|Rivals of Ixalan|167|R|{1}{U}{R}|Creature - Shapeshifter Pirate|2|2|Raid — If you attacked with a creature this turn, you may have Protean Raider enter the battlefield as a copy of any creature on the battlefield.| Storm the Vault|Rivals of Ixalan|173|R|{2}{U}{R}|Legendary Enchantment|||Whenever one or more creatures you control deal combat damage to a player, create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool."$At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault.| Vault of Catlacan|Rivals of Ixalan|173|R||Legendary Land|||(Transforms from Storm the Vault.)${T}: Add one mana of any color to your mana pool.${T}: Add {U} to your mana pool for each artifact you control.| Awakened Amalgam|Rivals of Ixalan|175|R|{4}|Artifact Creature - Golem|0|0|Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control.| Captain's Hook|Rivals of Ixalan|177|R|{3}|Artifact - Equipment|||Equipped creature gets +2/+0, has menace, and is a Pirate in addition to its other creature types.$Whenever Captain's Hook becomes unattached from a permanent, destroy that permanent.$Equip {1}| Gleaming Barrier|Rivals of Ixalan|178|C|{2}|Artifact Creature - Wall|0|4|Defender$When Gleaming Barrier dies, create a colorless Treasure artifact token with "{t}, Sacrifice this artifact: Add one mana of any color to your mana pool."| +Golden Guardian|Rivals of Ixalan|179|R|{4}|Creature - Golem|4|4|Defender${2}: This creature fights another target creature you control. When this dies this turn, return it to the battlefield transformed.| +Gold-Forge Garrison|Rivals of Ixalan|179|R||Land|||{t}: Add two mana of any one color to your mana pool.${4}, {T}: Create a 4/4 colorless Golem artifact creature token.| The Immortal Sun|Rivals of Ixalan|180|M|{6}|Legendary Artifact|||Players can't activate planeswalkers' loyalty abilities.$At the beginning of your draw step, draw an additional card.$Spells you cast cost {1} less to cast.$Creatures you control get +1/+1.| Silent Gravestone|Rivals of Ixalan|182|R|{1}|Artifact|||Cards in graveyards can't be the targets of spells or abilities.${4}, {t}: Exile Silent Gravestone and all cards from all graveyards. Draw a card.| Evolving Wilds|Rivals of Ixalan|186|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| @@ -32767,7 +32778,6 @@ Angrath's Ambusher|Rivals of Ixalan|202|U|{2}{B}|Creature - Orc Pirate|2|3|Angra Swab Goblin|Rivals of Ixalan|203|C|{1}{R}|Creature - Goblin Pirate|2|2|| Angrath's Fury|Rivals of Ixalan|204|R|{3}{B}{R}|Sorcery|||Destroy target creature. Angrath's Fury deals 3 damage to target player. You may search your library and/or graveyard for a card named Angrath, Minotaur Pirate, reveal it, and put it into your hand. If you search your library this way, shuffle it.| Cinder Barrens|Rivals of Ixalan|205|C||Land|||Cinder Barrens enters the battlefield tapped.${T}: Add {B} or {R} to your mana pool.| -Forerunner of the Legion|Rivals of Ixalan|9|U|{9}|Creature - Vampire Knight|2|2|When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it.$Whenever another Vampire enters the battlefield under your control, target creature gets +1/+1 until end of turn. Amateur Auteur|Unstable|3|C|{1}{W}|Creature - Human|2|2|Sacrifice Amateur Auteur: Destroy target enchantment.| Angelic Rocket|Unstable|139|R|{8}|Host Creature - Angel|4|4|Flying$When this creature enters the battlefield, you may destroy target nonland permanent.| As Luck Would Have It|Unstable|102|R|{G}|Enchantment|||Hexproof$Whenever you roll a die, put a number of luck counters on As Luck Would Have It equal to the result. Then is there are 100 or more luck counters on As Luck Would Have It, you win the game. (Count both rolls if you reroll a die.)|